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

Contents of /bin/tracker_service.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 6389 - (hide annotations) (download) (as text)
Fri Aug 24 09:27:16 2007 UTC (5 years, 9 months ago) by thijs
File MIME type: text/script
File size: 50107 byte(s)
textfix
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 fw 3069 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     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     A("http://www.cve.mitre.org/cve/index.html", "CVE database"),
143     """, 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 3071 ('status/release/oldstable',
164     'Vulnerable packages in the oldstable suite'),
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     def page_status_release_oldstable(self, path, params, url):
643     return self.page_status_release_stable_oldstable('oldstable',
644     params, url)
645 fw 2482
646     def page_status_release_testing(self, path, params, url):
647 fw 5100 bf = BugFilterNoDSA(params)
648 fw 2491
649 fw 2482 def gen():
650     old_pkg_name = ''
651     for (pkg_name, bug_name, archive, urgency,
652 fw 5100 sid_vulnerable, ts_fixed, remote, no_dsa) \
653     in self.db.cursor().execute(
654 fw 2482 """SELECT package, bug, section, urgency, unstable_vulnerable,
655 fw 5100 testing_security_fixed, remote, no_dsa
656 fw 2482 FROM testing_status"""):
657 fw 2491 if bf.urgencyFiltered(urgency):
658     continue
659     if bf.remoteFiltered(remote):
660     continue
661 fw 5100 if bf.nodsaFiltered(no_dsa):
662     continue
663 fw 2491
664 fw 2482 if pkg_name == old_pkg_name:
665     pkg_name = ''
666     else:
667     old_pkg_name = pkg_name
668     if archive <> 'main':
669     pkg_name = "%s (%s)" % (pkg_name, archive)
670    
671 fw 2488 if remote is None:
672     remote = ''
673     elif remote:
674     remote = 'yes'
675     else:
676     remote = 'no'
677    
678 fw 2482 if ts_fixed:
679     status = 'fixed in testing-security'
680     else:
681     if sid_vulnerable:
682     status = self.make_red('unstable is vulnerable')
683     else:
684     status = self.make_dangerous('fixed in unstable')
685    
686     if urgency == 'unknown':
687     urgency = ''
688    
689     yield (pkg_name, self.make_xref(url, bug_name),
690 fw 2488 urgency, remote, status)
691 fw 2482
692     return self.create_page(
693     url, 'Vulnerable source packages in the testing suite',
694     [make_menu(url.scriptRelative,
695     ("status/dtsa-candidates", "Candidates for DTSAs")),
696 fw 2491 bf.actions(url),
697 fw 2488 make_table(gen(), caption=("Package", "Bug", "Urgency",
698     "Remote"))])
699 fw 2482
700     def page_status_release_unstable(self, path, params, url):
701 fw 2491 bf = BugFilter(params)
702    
703 fw 2482 def gen():
704     old_pkg_name = ''
705 fw 2491 for (pkg_name, bug_name, section, urgency, remote) \
706 fw 2482 in self.db.cursor().execute(
707     """SELECT DISTINCT sp.name, st.bug_name,
708 fw 2491 sp.archive, st.urgency,
709     (SELECT range_remote FROM nvd_data
710     WHERE cve_name = st.bug_name)
711 fw 2482 FROM source_package_status AS st, source_packages AS sp
712     WHERE st.vulnerable AND st.urgency <> 'unimportant'
713     AND sp.rowid = st.package AND sp.release = 'sid'
714     AND sp.subrelease = ''
715     ORDER BY sp.name, st.bug_name"""):
716 fw 2491 if bf.urgencyFiltered(urgency):
717     continue
718     if bf.remoteFiltered(remote):
719     continue
720    
721 fw 2482 if pkg_name == old_pkg_name:
722     pkg_name = ''
723     else:
724     old_pkg_name = pkg_name
725     if section <> 'main':
726     pkg_name = "%s (%s)" % (pkg_name, section)
727     else:
728     pkg_name = self.make_xref(url, pkg_name)
729    
730 fw 2491 if remote is None:
731     remote = ''
732     elif remote:
733     remote = 'yes'
734     else:
735     remote = 'no'
736    
737 fw 2482 if urgency == 'unknown':
738     urgency = ''
739     elif urgency == 'high':
740     urgency = self.make_red(urgency)
741    
742 fw 2491 yield pkg_name, self.make_xref(url, bug_name), urgency, remote
743 fw 2482
744    
745     return self.create_page(
746 fw 3014 url, 'Vulnerable source packages in the unstable suite',
747 fw 2482 [P("""Note that the list below is based on source packages.
748     This means that packages are not listed here once a new,
749     fixed source version has been uploaded to the archive, even
750     if there are still some vulnerably binary packages present
751     in the archive."""),
752 fw 2491 bf.actions(url),
753     make_table(gen(), caption=('Package', 'Bug', 'Urgency',
754     'Remote'))])
755 fw 2482
756     def page_status_dtsa_candidates(self, path, params, url):
757 fw 2491 bf = BugFilter(params)
758    
759 fw 2482 def gen():
760     old_pkg_name = ''
761 fw 2491 for (pkg_name, bug_name, archive, urgency, stable_later,
762     remote) \
763 fw 2482 in self.db.cursor().execute(
764     """SELECT package, bug, section, urgency,
765     (SELECT testing.version_id < stable.version_id
766     FROM source_packages AS testing, source_packages AS stable
767     WHERE testing.name = testing_status.package
768 fw 5655 AND testing.release = 'lenny'
769 fw 2482 AND testing.subrelease = ''
770     AND testing.archive = testing_status.section
771     AND stable.name = testing_status.package
772 fw 5655 AND stable.release = 'etch'
773 fw 2482 AND stable.subrelease = 'security'
774 fw 2491 AND stable.archive = testing_status.section),
775     (SELECT range_remote FROM nvd_data
776     WHERE cve_name = bug)
777 fw 2482 FROM testing_status
778     WHERE (NOT unstable_vulnerable)
779     AND (NOT testing_security_fixed)"""):
780 fw 2491 if bf.urgencyFiltered(urgency):
781     continue
782     if bf.remoteFiltered(remote):
783     continue
784    
785 fw 2482 if pkg_name == old_pkg_name:
786     pkg_name = ''
787     migration = ''
788     else:
789     old_pkg_name = pkg_name
790     migration = A(self.url_testing_status(url, pkg_name),
791     "check")
792     if archive <> 'main':
793     pkg_name = "%s (%s)" % (pkg_name, archive)
794     else:
795     pkg_name = self.make_source_package_ref(url, pkg_name)
796    
797 fw 2491 if remote is None:
798     remote = ''
799     elif remote:
800     remote = 'yes'
801     else:
802     remote = 'no'
803    
804 fw 2482 if urgency == 'unknown':
805     urgency = ''
806     elif urgency == 'high':
807     urgency = self.make_red(urgency)
808    
809     if stable_later:
810     notes = "(fixed in stable?)"
811     else:
812     notes = ''
813    
814     yield (pkg_name, migration, self.make_xref(url, bug_name),
815 fw 2491 urgency, remote, notes)
816 fw 2482
817     return self.create_page(
818     url, "Candidates for DTSAs",
819     [P("""The table below lists packages which are fixed
820     in unstable, but unfixed in testing. Use the testing migration
821 fw 2679 checker to find out why they have not entered testing yet."""),
822 fw 2482 make_menu(url.scriptRelative,
823     ("status/release/testing",
824     "List of vulnerable packages in testing")),
825 fw 2491 bf.actions(url),
826 fw 2482 make_table(gen(),
827 fw 2491 caption=("Package", "Migration", "Bug", "Urgency",
828     "Remote"))])
829 fw 2482
830     def page_status_todo(self, path, params, url):
831 fw 4005 hide_check = params.get('hide_check', False)
832     if hide_check:
833     flags = A(url.updateParamsDict({'hide_check' : None}),
834     'Show "check" TODOs')
835     else:
836     flags = A(url.updateParamsDict({'hide_check' : '1'}),
837     'Hide "check" TODOs')
838    
839 fw 2482 def gen():
840 fw 4005 for (bug, description) in self.db.getTODOs(hide_check=hide_check):
841 fw 2482 yield self.make_xref(url, bug), description
842     return self.create_page(
843     url, "Bugs with TODO items",
844 fw 4005 [P(flags),
845     make_table(gen(),
846 fw 2482 caption=("Bug", "Description"))])
847    
848     def page_status_itp(self, path, params, url):
849     def gen():
850     old_pkg = ''
851     for pkg, bugs, debian_bugs in self.db.getITPs(self.db.cursor()):
852     if pkg == old_pkg:
853     pkg = ''
854     else:
855     old_pkg = pkg
856     yield (pkg, self.make_xref_list(url, bugs),
857     self.make_debian_bug_list(url, debian_bugs))
858     return self.create_page(
859     url, "ITPs with potential security issues",
860     [make_table(gen(), caption=("Package", "Issue", "Debian Bugs"),
861     replacement="No ITP bugs are currently known.")])
862    
863     def page_data_unknown_packages(self, path, params, url):
864     def gen():
865     for name, bugs in self.db.getUnknownPackages(self.db.cursor()):
866     yield name, self.make_xref_list(url, bugs)
867     return self.create_page(
868     url, "Unknown packages",
869     [P("""Sometimes, a package referenced in a bug report
870     cannot be found in the database. This can be the result of a spelling
871 thijs 6389 error, or a historic entry refers to a
872     package which is no longer in the archive."""),
873 fw 2482 make_table(gen(), caption=("Package", "Bugs"),
874     replacement="No unknown packages are referenced in the database.")])
875    
876     def page_data_missing_epochs(self, path, params, url):
877     def gen():
878     old_bug = ''
879     old_pkg = ''
880     for bug, pkg, ver1, ver2 in self.db.cursor().execute(
881     """SELECT DISTINCT bug_name, n.package,
882     n.fixed_version, sp.version
883     FROM package_notes AS n, source_packages AS sp
884     WHERE n.package_kind = 'source'
885     AND n.fixed_version NOT LIKE '%:%'
886     AND n.fixed_version <> '0'
887     AND n.bug_origin = ''
888     AND sp.name = n.package
889     AND sp.version LIKE '%:%'
890     ORDER BY bug_name, package"""):
891     if bug == old_bug:
892     bug = ''
893     else:
894     old_bug = bug
895     old_pkg = ''
896     bug = self.make_xref(url, bug)
897     if pkg == old_pkg:
898     pkg = ''
899     else:
900     old_pkg = pkg
901     pkg = self.make_source_package_ref(url, pkg)
902     yield bug, pkg, ver1, ver2
903    
904     return self.create_page(
905     url, "Missing epochs in package versions",
906     [make_table(gen(),
907     caption=("Bug", "Package", "Version 1", "Version 2"),
908     replacement="No source package version with missing epochs.")])
909    
910 fw 3136 def page_data_latently_vulnerable(self, path, params, url):
911     def gen():
912     for pkg, bugs in self.db.cursor().execute(
913     """SELECT package, string_set(bug_name)
914     FROM package_notes AS p1
915     WHERE release <> ''
916 fw 5103 AND (bug_name LIKE 'CVE-%' OR bug_name LIKE 'TEMP-%')
917 fw 3136 AND NOT EXISTS (SELECT 1 FROM package_notes AS p2
918     WHERE p2.bug_name = p1.bug_name
919     AND p2.package = p1.package
920     AND release = '')
921     AND EXISTS (SELECT 1 FROM source_packages
922     WHERE name = p1.package AND release = 'sid')
923     GROUP BY package
924     ORDER BY package"""):
925     pkg = self.make_source_package_ref(url, pkg)
926     bugs = bugs.split(',')
927     yield pkg, self.make_xref_list(url, bugs)
928    
929 fw 3166 def gen_unimportant():
930     for pkg, bugs in self.db.cursor().execute(
931     """SELECT package, string_set(bug_name)
932     FROM package_notes AS p1
933     WHERE release <> ''
934     AND urgency <> 'unimportant'
935 fw 5103 AND (bug_name LIKE 'CVE-%' OR bug_name LIKE 'TEMP-%')
936 fw 3166 AND EXISTS (SELECT 1 FROM package_notes AS p2
937     WHERE p2.bug_name = p1.bug_name
938     AND p2.package = p1.package
939     AND release = '')
940     AND NOT EXISTS (SELECT 1 FROM package_notes AS p2
941     WHERE p2.bug_name = p1.bug_name
942     AND p2.package = p1.package
943     AND urgency <> 'unimportant'
944     AND release = '')
945     AND EXISTS (SELECT 1 FROM source_packages
946     WHERE name = p1.package AND release = 'sid')
947     GROUP BY package
948     ORDER BY package"""):
949     pkg = self.make_source_package_ref(url, pkg)
950     bugs = bugs.split(',')
951     yield pkg, self.make_xref_list(url, bugs)
952    
953 fw 3136 return self.create_page(
954     url, "Latently vulnerable packages in unstable",
955     [P(
956     """A package is latently vulnerable in unstable if it is vulnerable in
957     any release, and there is no package note for the same vulnerability
958     and package in unstable (and the package is still available in
959     unstable, of course)."""),
960     make_table(gen(),
961     caption=("Package", "Bugs"),
962 fw 3166 replacement="No latently vulnerable packages were found."),
963     P(
964     """The next table lists issues which are marked unimportant for
965     unstable, but for which release-specific annotations exist which are
966     not unimportant."""),
967     make_table(gen_unimportant(),
968     caption=("Package", "Bugs"),
969     replacement=
970     "No packages with unimportant latent vulnerabilities were found."),
971     ])
972 fw 3136
973 fw 2482 def page_data_releases(self, path, params, url):
974     def gen():
975     for (rel, subrel, archive, sources, archs) \
976     in self.db.availableReleases():
977     if sources:
978     sources = 'yes'
979     else:
980     sources = 'no'
981     yield rel, subrel, archive, sources, make_list(archs)
982     return self.create_page(
983     url, "Available releases",
984     [P("""The security issue database is checked against
985     the Debian releases listed in the table below."""),
986     make_table(gen(),
987     caption=("Release", "Subrelease", "Archive",
988     "Sources", "Architectures"))])
989    
990     def page_data_funny_versions(self, path, params, url):
991     def gen():
992     for name, release, archive, version, source_version \
993     in self.db.getFunnyPackageVersions():
994     yield name, release, archive, source_version, version
995    
996     return self.create_page(
997     url, "Version conflicts between source/binary packages",
998     [P("""The table below lists source packages
999     which have a binary package of the same name, but with a different
1000     version. This means that extra care is necessary to determine
1001     the version of a package which has been fixed. (Note that
1002     the bug tracker prefers source versions to binary versions
1003     in this case.)"""),
1004     make_table(gen(),
1005     caption=("Package",
1006     "Release",
1007     "Archive",
1008     "Source Version",
1009     "Binary Version")),
1010     P("""Technically speaking, these version numbering is fine,
1011     but it makes version-based bug tracking quite difficult for these packages."""),
1012     P("""There are many binary packages which are built from source
1013     packages with different version numbering schemes. However, as
1014     long as none of the binary packages carries the same name as the
1015     source package, most confusion is avoided or can be easily
1016     explained.""")])
1017    
1018 fw 2554 def page_data_fake_names(self, path, params, url):
1019     def gen():
1020     for (bug, description) in self.db.getFakeBugs():
1021     yield self.make_xref(url, bug), description
1022     return self.create_page(
1023     url, "Automatically generated issue names",
1024     [P("""Some issues have not been assigned CVE names, but are still
1025     tracked by this database. In this case, the system automatically assigns
1026     a unique name. These names are not stable and can change when the database
1027     is updated, so they should not be used in external references."""),
1028     P('''The automatically generated names come in two flavors:
1029 fw 5103 the first kind starts with the string "''', CODE("TEMP-000000-"),
1030 fw 2554 '''". This means that no Debian bug has been assigned to this
1031     issue (or a bug has been created and is not recorded in this database).
1032     In the second kind of names, there is a Debian bug for the issue, and the "''',
1033     CODE("000000"), '''"part of the name is replaced with the
1034     Debian bug number.'''),
1035     make_table(gen(),
1036     caption=("Bug", "Description"))])
1037    
1038 fw 3051 def page_debsecan(self, path, params, url):
1039     obj = '/'.join(path)
1040     data = self.db.getDebsecan(obj)
1041     if data:
1042     return BinaryResult(data)
1043     else:
1044     return self.create_page(
1045     url, "Object not found",
1046     [P("The requested debsecan object has not been found.")],
1047     status=404)
1048    
1049 fw 2482 def create_page(self, url, title, body, search_in_page=False, status=200):
1050     append = body.append
1051     append(HR())
1052     if not search_in_page:
1053     append(self.make_search_button(url))
1054     append(P(A(url.scriptRelative(""), "Home"),
1055     " - ", A(url.absolute("http://secure-testing.debian.net/"),
1056     "Testing Security Team"),
1057     " - ", A(url.absolute("http://www.debian.org/security/"),
1058     "Debian Security"),
1059     " - ", A(url.absolute
1060     ("http://www.enyo.de/fw/impressum.html"),
1061     "Imprint")))
1062     if search_in_page:
1063     on_load = "selectSearch()"
1064     else:
1065     on_load = None
1066     return HTMLResult(self.add_title(title, body,
1067     head_contents=self.head_contents,
1068     body_attribs={'onload': on_load}),
1069     doctype=self.html_dtd(),
1070     status=status)
1071    
1072     def make_search_button(self, url):
1073     return FORM("Search for package or bug name: ",
1074     INPUT(type='text', name='query',
1075     onkeyup="onSearch(this.value)",
1076     onmousemove="onSearch(this.value)"),
1077     INPUT(type='submit', value='Go'),
1078 fw 3597 ' ',
1079 fw 3596 A(url.scriptRelative("data/report"), "Reporting problems"),
1080 fw 2482 method='get',
1081     action=url.scriptRelative(''))
1082    
1083     def url_cve(self, url, name):
1084     return url.absolute("http://cve.mitre.org/cgi-bin/cvename.cgi",
1085     name=name)
1086 fw 2488 def url_nvd(self, url, name):
1087     return url.absolute("http://nvd.nist.gov/nvd.cfm",
1088     cvename=name)
1089    
1090 fw 2482 def url_dsa(self, url, dsa, re_dsa=re.compile(r'^DSA-(\d+)(?:-\d+)?$')):
1091     match = re_dsa.match(dsa)
1092     if match:
1093     # We must determine the year because there is no generic URL.
1094     (number,) = match.groups()
1095     for (date,) in self.db.cursor().execute(
1096     "SELECT release_date FROM bugs WHERE name = ?", (dsa,)):
1097     (y, m, d) = date.split('-')
1098     return url.absolute("http://www.debian.org/security/%d/dsa-%d"
1099     % (int(y), int(number)))
1100     return None
1101    
1102     def url_debian_bug(self, url, debian):
1103     return url.absolute("http://bugs.debian.org/cgi-bin/bugreport.cgi",
1104     bug=str(debian))
1105     def url_debian_bug_pkg(self, url, debian):
1106     return url.absolute("http://bugs.debian.org/cgi-bin/pkgreport.cgi",
1107     pkg=debian)
1108     def url_pts(self, url, package):
1109     return url.absolute("http://packages.qa.debian.org/common/index.html",
1110     src=package)
1111     def url_testing_status(self, url, package):
1112     return url.absolute("http://bjorn.haxx.se/debian/testing.pl",
1113     package=package)
1114     def url_source_package(self, url, package, full=False):
1115     if full:
1116     return url.scriptRelativeFull("source-package/" + package)
1117     else:
1118     return url.scriptRelative("source-package/" + package)
1119     def url_binary_package(self, url, package, full=False):
1120     if full:
1121     return url.scriptRelativeFull("binary-package/" + package)
1122     else:
1123     return url.scriptRelative("binary-package/" + package)
1124    
1125     def make_xref(self, url, name):
1126     return A(url.scriptRelative(name), name)
1127    
1128     def make_xref_list(self, url, lst, separator=', '):
1129     return make_list(map(lambda x: self.make_xref(url, x), lst), separator)
1130    
1131     def make_debian_bug(self, url, debian):
1132     return A(self.url_debian_bug(url, debian), str(debian))
1133     def make_debian_bug_list(self, url, lst):
1134     return make_list(map(lambda x: self.make_debian_bug(url, x), lst))
1135    
1136     def make_cve_ref(self, url, cve, name=None):
1137     if name is None:
1138     name = cve
1139     return A(self.url_cve(url, cve), name)
1140    
1141 fw 2488 def make_nvd_ref(self, url, cve, name=None):
1142     if name is None:
1143     name = cve
1144     return A(self.url_nvd(url, cve), name)
1145    
1146 fw 2482 def make_dsa_ref(self, url, dsa, name=None):
1147     if name is None:
1148     name = dsa
1149     u = self.url_dsa(url, dsa)
1150     if u:
1151     return A(u, name)
1152     else:
1153     return name
1154    
1155     def make_pts_ref(self, url, pkg, name=None):
1156     if name is None:
1157     name = pkg
1158     return A(self.url_pts(url, pkg), name)
1159    
1160     def make_source_package_ref(self, url, pkg, title=None):
1161     if title is None:
1162     title = pkg
1163     return A(self.url_source_package(url, pkg), title)
1164     def make_binary_package_ref(self, url, pkg, title=None):
1165     if title is None:
1166     title = pkg
1167     return A(self.url_binary_package(url, pkg), title)
1168     def make_binary_packages_ref(self, url, lst):
1169     assert type(lst) <> types.StringType
1170     return make_list(map(lambda x: self.make_binary_package_ref(url, x),
1171     lst))
1172    
1173     def make_red(self, contents):
1174     return SPAN(contents, _class="red")
1175    
1176     def make_dangerous(self, contents):
1177     return SPAN(contents, _class="dangerous")
1178    
1179     def pre_dispatch(self):
1180     self.db.refresh()
1181    
1182     TrackerService(socket_name, db_name).run()

Properties

Name Value
svn:mime-type text/script

  ViewVC Help
Powered by ViewVC 1.1.5