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

Contents of /bin/tracker_service.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 33869 - (show annotations) (download) (as text)
Sun Apr 26 17:34:16 2015 UTC (8 hours, 11 minutes ago) by holger
File MIME type: text/script
File size: 72967 byte(s)
fix typo
1 #!/usr/bin/python
2
3 import sys
4 sys.path.insert(0,'../lib/python')
5 import bugs
6 import re
7 import security_db
8 from web_support import *
9 import json
10
11 if len(sys.argv) not in (3, 5):
12 print "usage: python tracker_service.py SOCKET-PATH DATABASE-PATH"
13 print " python tracker_service.py URL HOST PORT DATABASE-PATH"
14 sys.exit(1)
15 if len(sys.argv) == 3:
16 socket_name = sys.argv[1]
17 db_name = sys.argv[2]
18 webservice_base_class = WebService
19 else:
20 server_base_url = sys.argv[1]
21 server_address = sys.argv[2]
22 server_port = int(sys.argv[3])
23 socket_name = (server_base_url, server_address, server_port)
24 db_name = sys.argv[4]
25 webservice_base_class = WebServiceHTTP
26
27 def clean_dict(d):
28 """ taken from http://w3facility.org/question/exclude-emptynull-values-from-json-serialization/
29 Delete keys with the value ``None`` in a dictionary, recursively.
30
31 This alters the input so you may wish to ``copy`` the dict first.
32 """
33 # d.iteritems isn't used as you can't del or the iterator breaks.
34 for key, value in d.items():
35 if value is None:
36 del d[key]
37 elif isinstance(value, dict):
38 clean_dict(value)
39 return d # For convenience
40
41 class BugFilter:
42 default_action_list = [('high_urgency', 'high', 'urgency'),
43 ('medium_urgency', 'medium', 'urgency'),
44 ('low_urgency', 'low', 'urgency'),
45 ('unimportant_urgency', 'unimportant', 'urgency'),
46 ('unassigned_urgency', 'not yet assigned', 'urgency'),
47 ('endoflife_urgency', 'end-of-life', 'urgency'),
48
49 ('remote', 'hide remote scope', 'scope'),
50 ('local', 'hide local scope', 'scope'),
51 ('unclear', 'hide unclear scope', 'scope'),
52
53 ('undetermined_issues', 'include issues to be checked (shown in purple)', 'extra'),]
54
55 def __init__(self, params, nonodsa=False):
56 self.action_list = self.default_action_list
57 if not nonodsa:
58 self.action_list = self.default_action_list + [('nodsa', 'include issues tagged <no-dsa>', 'extra')]
59 self.params = {}
60 for (prop, desc, field) in self.action_list:
61 self.params[prop] = int(params.get(prop, (0,))[0])
62 self.filters=params.get('filter')
63 if not self.filters:
64 self.filters=['high_urgency', 'medium_urgency', 'low_urgency', 'unassigned_urgency']
65
66 def actions(self, url):
67 """Returns a HTML snippet which can be used to change the filter."""
68
69 l = []
70 l.append(INPUT(type='hidden', name='filter', value='1'))
71 for (prop, desc, field) in self.action_list:
72 if prop in self.filters:
73 l.append(LABEL(INPUT(desc, type='checkbox', name='filter', value=prop, onChange='this.form.submit()', checked='checked'), rel=field))
74 self.params[prop]=1
75 else:
76 l.append(LABEL(INPUT(desc, type='checkbox', name='filter', value=prop, onChange='this.form.submit()'), rel=field))
77
78 return FORM(tag("SPAN",l, id="filters"),
79 tag("NOSCRIPT", [INPUT(type='submit', value='Apply')]),
80 method='get')
81
82 def urgencyFiltered(self, urg, vuln):
83 """Returns True for urgencies that should be filtered."""
84 filterlow = not self.params['low_urgency'] and \
85 urg in ('low', 'low**')
86 filtermed = not self.params['medium_urgency'] and \
87 urg in ('medium', 'medium**')
88 filterhigh = not self.params['high_urgency'] and \
89 urg in ('high', 'high**')
90 filterund = not self.params['undetermined_issues'] and vuln == 2
91 filteruni = not self.params['unimportant_urgency'] \
92 and urg == 'unimportant'
93 filteruna = not self.params['unassigned_urgency'] \
94 and urg == 'not yet assigned'
95 filterend = not self.params['endoflife_urgency'] \
96 and urg == 'end-of-life'
97 return filterlow or filtermed or filterhigh or filterund or filteruni or filteruna or filterend
98
99 def remoteFiltered(self, remote):
100 filterr = self.params['remote'] and remote and remote is not None
101 filterl = self.params['local'] and not remote and remote is not None
102 filteru = self.params['unclear'] and remote is None
103 return filterr or filterl or filteru
104
105 def nodsaFiltered(self, nodsa):
106 """Returns True for no DSA issues if filtered."""
107 return nodsa and not self.params['nodsa']
108
109 class TrackerService(webservice_base_class):
110 head_contents = compose(
111 LINK(' ', href="/tracker/style.css"),
112 SCRIPT(' ', src="/tracker/script.js"),
113 ).toHTML()
114
115 nvd_text = P('''If a "**" is included, the urgency field was automatically
116 assigned by the NVD (National Vulnerability Database). Note that this
117 rating is automatically derived from a set of known factors about the
118 issue (such as access complexity, confidentiality impact, exploitability,
119 remediation level, and others). Human intervention is involved in
120 determining the values of these factors, but the rating itself comes
121 from a fully automated formula.''')
122
123 def __init__(self, socket_name, db_name):
124 webservice_base_class.__init__(self, socket_name)
125 self.db = security_db.DB(db_name)
126 self.register('', self.page_home)
127 self.register('*', self.page_object)
128 self.register('redirect/*', self.page_redirect)
129 self.register('source-package/*', self.page_source_package)
130 self.register('status/release/oldoldstable',
131 self.page_status_release_oldoldstable)
132 self.register('status/release/oldstable',
133 self.page_status_release_oldstable)
134 self.register('status/release/stable', self.page_status_release_stable)
135 self.register('status/release/stable-backports',
136 self.page_status_release_stable_backports)
137 self.register('status/release/oldstable-backports',
138 self.page_status_release_oldstable_backports)
139 self.register('status/release/oldoldstable-backports',
140 self.page_status_release_oldoldstable_backports)
141 self.register('status/release/testing',
142 self.page_status_release_testing)
143 self.register('status/release/unstable',
144 self.page_status_release_unstable)
145 self.register('status/dtsa-candidates',
146 self.page_status_dtsa_candidates)
147 self.register('status/todo', self.page_status_todo)
148 self.register('status/undetermined', self.page_status_undetermined)
149 self.register('status/unimportant', self.page_status_unimportant)
150 self.register('status/itp', self.page_status_itp)
151 self.register('status/unreported', self.page_status_unreported)
152 self.register('data/unknown-packages', self.page_data_unknown_packages)
153 self.register('data/missing-epochs', self.page_data_missing_epochs)
154 self.register('data/latently-vulnerable',
155 self.page_data_latently_vulnerable)
156 self.register('data/releases', self.page_data_releases)
157 self.register('data/funny-versions', self.page_data_funny_versions)
158 self.register('data/fake-names', self.page_data_fake_names)
159 self.register('data/pts/1', self.page_data_pts)
160 self.register('data/json', self.page_json)
161 self.register('debsecan/**', self.page_debsecan)
162 self.register('data/report', self.page_report)
163 self.register('style.css', self.page_style_css)
164 self.register('logo.png', self.page_logo_png)
165 self.register('script.js', self.page_script_js)
166
167 def page_style_css(self, path, params, url):
168 f=open('../static/style.css', 'r')
169 content=f.read()
170 f.close()
171 return BinaryResult(content,'text/css')
172
173 def page_logo_png(self, path, params, url):
174 f=open('../static/logo.png', 'r')
175 content=f.read()
176 f.close()
177 return BinaryResult(content,'image/png')
178
179 def page_script_js(self, path, params, url):
180 f=open('../static/script.js', 'r')
181 content=f.read()
182 f.close()
183 return BinaryResult(content,'text/javascript')
184
185
186 def page_home(self, path, params, url):
187 query = params.get('query', ('',))[0]
188 if query:
189 if '/' in query:
190 return self.page_not_found(url, query)
191 else:
192 return RedirectResult(url.scriptRelativeFull(query))
193
194 return self.create_page(
195 url, 'Security Bug Tracker',
196 [P(
197 """The data in this tracker comes solely from the bug database maintained
198 by Debian's security team located in the testing-security Subversion """,
199 A("https://anonscm.debian.org/viewvc/secure-testing/data/", "repository"),
200 """. The data represented here is derived from: """,
201 A("https://www.debian.org/security/#DSAS", "DSAs"),
202 """ issued by the Security Team; issues tracked in the """,
203 A("https://cve.mitre.org/cve/", "CVE database"),
204 """, issues tracked in the """,
205 A("https://nvd.nist.gov/", "National Vulnerability Database"),
206 """ (NVD), maintained by NIST; and security issues
207 discovered in Debian packages as reported in the BTS."""),
208 P("""All external data (including Debian bug reports and official Debian
209 security advisories) must be added to this database before it appears
210 here. Please help us keep this information up-to-date by """,
211 A(url.scriptRelative("data/report"), "reporting"),
212 """ any discrepancies or change of states that you are
213 aware of and/or help us improve the quality of this information by """,
214 A(url.scriptRelative("data/report"), "participating"),
215 "."),
216
217 NAV(make_menu(
218 url.scriptRelative,
219 ('status/release/unstable',
220 'Vulnerable packages in the unstable suite'),
221 ('status/release/testing',
222 'Vulnerable packages in the testing suite'),
223 ('status/release/stable',
224 'Vulnerable packages in the stable suite'),
225 ('status/release/stable-backports',
226 'Vulnerable packages in backports for stable'),
227 ('status/release/oldstable',
228 'Vulnerable packages in the oldstable suite'),
229 ('status/release/oldstable-backports',
230 'Vulnerable packages in backports for oldstable'),
231 ('status/release/oldoldstable',
232 'Vulnerable packages in the oldoldstable suite'),
233 ('status/release/oldoldstable-backports',
234 'Vulnerable packages in backports for oldoldstable'),
235 ('status/dtsa-candidates', "Candidates for DTSAs"),
236 ('status/todo', 'TODO items'),
237 ('status/undetermined', 'Packages that may be vulnerable but need to be checked (undetermined issues)'),
238 ('status/unimportant', 'Packages that have open unimportant issues'),
239 ('status/itp', 'ITPs with potential security issues'),
240 ('status/unreported', 'Open vulnerabilities without filed Debian bugs'),
241 ('data/unknown-packages',
242 'Packages names not found in the archive'),
243 ('data/fake-names', 'Tracked issues without a CVE name'),
244 ('data/missing-epochs',
245 'Package versions which might lack an epoch'),
246 ('data/latently-vulnerable',
247 'Packages which are latently vulnerable in unstable'),
248 ('data/funny-versions',
249 'Packages with strange version numbers'),
250 ('data/releases',
251 'Covered Debian releases and architectures'),
252 ('data/json',
253 'All information in JSON format')
254 )),
255
256 self.make_search_button(url),
257 P("""(You can enter CVE names, Debian bug numbers and package
258 names in the search forms.)"""),
259
260 H3("External interfaces"),
261 P("""If you want to automatically open a relevant web page for
262 some object, use the """,
263 CODE(str(url.scriptRelative("redirect/")), EM("object")),
264 """ URL. If no information is contained in this database,
265 the browser is automatically redirected to the corresponding external
266 data source.""")],
267 search_in_page=True)
268
269 def page_object(self, path, params, url):
270 obj = path[0]
271 return self.page_object_or_redirect(url, obj, False)
272
273 def page_redirect(self, path, params, url):
274 if path == ():
275 obj = ''
276 else:
277 obj = path[0]
278 return self.page_object_or_redirect(url, obj, True)
279
280 def page_object_or_redirect(self, url, obj, redirect):
281 c = self.db.cursor()
282
283 if not obj:
284 # Redirect to start page.
285 return RedirectResult(url.scriptRelativeFull(""))
286
287 # Attempt to decode a bug number. TEMP-nnn bugs (but not
288 # TEMP-nnn-mmm bugs) are treated as bug references, too.
289 bugnumber = 0
290 fake_bug = False
291 try:
292 if obj[0:5] == 'FAKE-' or obj[0:5] == 'TEMP-':
293 bugnumber = int(obj[5:])
294 fake_bug = True
295 else:
296 bugnumber = int(obj)
297 except ValueError:
298 pass
299 if bugnumber:
300 buglist = list(self.db.getBugsFromDebianBug(c, bugnumber))
301 if buglist:
302 return self.page_debian_bug(url, bugnumber, buglist, fake_bug)
303 if redirect:
304 return RedirectResult(self.url_debian_bug(url, str(bugnumber)),
305 permanent=False)
306
307 if 'A' <= obj[0] <= 'Z':
308 # Bug names start with a capital letter.
309 return self.page_bug(url, obj, redirect)
310
311 if self.db.isSourcePackage(c, obj):
312 return RedirectResult(self.url_source_package(url, obj, full=True))
313
314 return self.page_not_found(url, obj)
315
316 def page_bug(self, url, name, redirect):
317 # FIXME: Normalize CAN-* to CVE-* when redirecting. Too many
318 # people still use CAN.
319 if redirect and name[0:4] == 'CAN-':
320 name = 'CVE-' + name[4:]
321
322 cursor = self.db.cursor()
323 try:
324 bug = bugs.BugFromDB(cursor, name)
325 except ValueError:
326 if redirect:
327 if name[0:4] == 'CVE-':
328 return RedirectResult(self.url_cve(url, name),
329 permanent=False)
330 return self.page_not_found(url, name)
331 if bug.name <> name or redirect:
332 # Show the normalized bug name in the browser address bar.
333 return RedirectResult(url.scriptRelativeFull(bug.name))
334
335 page = []
336
337 def gen_header():
338 yield B("Name"), bug.name
339
340 nvd = self.db.getNVD(cursor, bug.name)
341
342 if nvd and nvd.cve_desc:
343 yield B("Description"), nvd.cve_desc
344 elif bug.description:
345 yield B("Description"), bug.description
346
347 source = bug.name.split('-')[0]
348 if source == 'CVE':
349 source_xref = compose(self.make_cve_ref(url, bug.name, 'CVE'),
350 " (at ",
351 self.make_nvd_ref(url, bug.name,
352 'NVD'),
353 "; ",
354 self.make_osssec_bug_ref(url, bug.name, 'oss-sec'),
355 ", ",
356 self.make_fulldisc_bug_ref(url, bug.name, 'fulldisc'),
357 ", ",
358 self.make_osvdb_bug_ref(url, bug.name, 'OSVDB'),
359 ", ",
360 self.make_edb_bug_ref(url, bug.name, 'EDB'),
361 ", ",
362 self.make_metasploit_bug_ref(url, bug.name, 'Metasploit'),
363 ", ",
364 self.make_rhbug_ref(url, bug.name,
365 'Red Hat'),
366 ", ",
367 self.make_ubuntu_bug_ref(url, bug.name, 'Ubuntu'),
368 ", ",
369 self.make_gentoo_bug_ref(url, bug.name, 'Gentoo'),
370 ", ",
371 self.make_suse_bug_ref(url, bug.name, 'SuSE'),
372 ", ",
373 self.make_mageia_bug_ref(url, bug.name, 'Mageia'),
374 ", ",
375 A(url.absolute('http://oss-security.openwall.org/wiki/vendors'), 'more'),
376 ")")
377 elif source == 'DSA':
378 source_xref = self.make_dsa_ref(url, bug.name, 'Debian')
379 elif source == 'DTSA':
380 source_xref = 'Debian Testing Security Team'
381 elif source == 'DLA':
382 source_xref = 'Debian LTS Team'
383 elif source == 'TEMP':
384 source_xref = (
385 'Automatically generated temporary name. Not for external reference.')
386 else:
387 source_xref = None
388
389 if source_xref:
390 yield B("Source"), source_xref
391
392 xref = list(self.db.getBugXrefs(cursor, bug.name))
393 if xref:
394 yield B("References"), self.make_xref_list(url, xref)
395
396 if nvd:
397 nvd_range = nvd.rangeString()
398 if nvd.severity:
399 nvd_severity = nvd.severity.lower()
400 if nvd_range:
401 nvd_severity = "%s (attack range: %s)" \
402 % (nvd_severity, nvd_range)
403 yield B("NVD severity"), nvd_severity
404
405 debian_bugs = bug.getDebianBugs(cursor)
406 if debian_bugs:
407 yield (B("Debian Bugs"),
408 self.make_debian_bug_list(url, debian_bugs))
409
410 if not bug.not_for_us:
411 for (release, status, reason) in bug.getStatus(cursor):
412 if status == 'undetermined':
413 reason = self.make_purple(reason)
414 elif status <> 'fixed':
415 reason = self.make_red(reason)
416 yield B('Debian/%s' % release), reason
417
418 page.append(make_table(gen_header()))
419
420 if bug.notes:
421
422 def gen_source():
423 old_pkg = ''
424 for (package, release, version, vulnerable) \
425 in self.db.getSourcePackages(cursor, bug.name):
426 if package == old_pkg:
427 package = ''
428 else:
429 old_pkg = package
430 package = compose(
431 self.make_source_package_ref(url, package),
432 " (", self.make_pts_ref(url, package, 'PTS'), ")")
433 if vulnerable == 1:
434 vuln = self.make_red('vulnerable')
435 version = self.make_red(version)
436 elif vulnerable == 2:
437 vuln = self.make_purple('undetermined')
438 version = self.make_purple(version)
439 else:
440 vuln = 'fixed'
441
442 yield package, ', '.join(release), version, vuln
443
444 page.append(make_table(gen_source(),
445 title=H2('Vulnerable and fixed packages'),
446 caption=("Source Package", "Release", "Version", "Status"),
447 introduction=P('The table below lists information on source packages.')))
448
449 def gen_data():
450 notes_sorted = bug.notes[:]
451 notes_sorted.sort(lambda a, b: cmp(a.package, b.package))
452 for n in notes_sorted:
453 if n.release:
454 rel = str(n.release)
455 else:
456 rel = '(unstable)'
457 urgency = str(n.urgency)
458 if urgency == 'end-of-life':
459 urgency = self.make_purple('end-of-life')
460 if n.fixed_version:
461 ver = str(n.fixed_version)
462 if ver == '0':
463 ver = '(not affected)'
464 urgency = ''
465 else:
466 ver = self.make_red('(unfixed)')
467 if urgency == 'not yet assigned':
468 urgency = ''
469
470 pkg = n.package
471 pkg_kind = n.package_kind
472 if pkg_kind == 'source':
473 pkg = self.make_source_package_ref(url, pkg)
474 elif pkg_kind == 'itp':
475 pkg_kind = 'ITP'
476 rel = ''
477 ver = ''
478 urgency = ''
479
480 bugs = n.bugs
481 bugs.sort()
482 bugs = make_list(
483 map(lambda x: self.make_debian_bug(url, x), bugs))
484 if n.bug_origin:
485 origin = self.make_xref(url, n.bug_origin)
486 else:
487 origin = ''
488 yield (pkg, pkg_kind, rel, ver, urgency, origin, bugs)
489
490 page.append(
491 make_table(gen_data(),
492 caption=("Package", "Type", "Release", "Fixed Version",
493 "Urgency", "Origin", "Debian Bugs"),
494 introduction=P("The information below is based on the following data on fixed versions.")))
495
496 if bug.comments:
497 page.append(H2("Notes"))
498 def gen_comments():
499 for (t, c) in bug.comments:
500 yield c
501 page.append(make_pre(gen_comments()))
502
503 return self.create_page(url, bug.name, page)
504
505 def page_debian_bug(self, url, bugnumber, buglist, fake_bug):
506 if fake_bug:
507 new_buglist = []
508 for b in buglist:
509 (bug_name, urgency, description) = b
510 if bug_name[0:5] == 'FAKE-' or bug_name[0:5] == 'TEMP-':
511 new_buglist.append(b)
512 if len(new_buglist) > 0:
513 # Only replace the bug list if there are still fake
514 # bug reports.
515 buglist = new_buglist
516
517 if len(buglist) == 1:
518 # Single issue, redirect.
519 return RedirectResult(url.scriptRelativeFull(buglist[0][0]))
520
521 def gen():
522 for (name, urgency, description) in buglist:
523 if urgency == "unknown":
524 urgency = ""
525 yield self.make_xref(url, name), urgency, description
526
527 if fake_bug:
528 intro = """The URL you used contained a non-stable name
529 based on a Debian bug number. This name cannot be mapped to a specific
530 issue. """
531 else:
532 intro = ""
533
534 return self.create_page(
535 url, "Information related to Debian bug #%d" % bugnumber,
536 [P(intro + "The following issues reference to Debian bug ",
537 self.make_debian_bug(url, bugnumber), ":"),
538 make_table(gen(),
539 caption=("Name", "Urgency", "Description"))])
540
541 def page_not_found(self, url, query):
542 return self.create_page(url, 'Not found',
543 [P('Your query ',
544 CODE(query),
545 ' matched no results.')],
546 status=404)
547
548 def page_report(self, path, params, url):
549 return self.create_page(
550 url, 'Reporting discrepancies in the data',
551 [P("""The data in this tracker is always in flux, as bugs are fixed and new
552 issues disclosed, the data contained herein is updated. We strive to
553 maintain complete and accurate state information, and appreciate any
554 updates in status, information or new issues."""),
555 P("There are three ways that you can report updates to this information:"),
556 make_numbered_list(
557 [P("""IRC: We can be found at """,
558 CODE("irc.oftc.net"),
559 ", ",
560 CODE("#debian-security"),
561 """. If you have information to report, please go ahead and join
562 the channel and tell us. Please feel free to state the issue,
563 regardless if there is someone who has acknowledged you. Many of us
564 idle on this channel and may not be around when you join, but we read
565 the backlog and will see what you have said. If you require a
566 response, do not forget to let us know how to get a hold of you."""),
567 P("Mailing list: Our mailing list is: ",
568 A("mailto:debian-security-tracker@lists.debian.org",
569 "debian-security-tracker@lists.debian.org")),
570 P("""Helping out: We welcome people who wish to join us in tracking
571 issues. The process is designed to be easy to learn and participate,
572 please read our """,
573 A("http://security-team.debian.org/security_tracker.html",
574 "Introduction"),
575 """ to get familiar with how things work. Join us on
576 our mailing list, and on IRC and request to be added to the Alioth """,
577 A("https://alioth.debian.org/projects/secure-testing/", "project"),
578 """. We are really quite friendly. If you have a
579 question about how things work, don't be afraid to ask, we would like
580 to improve our documentation and procedures, so feedback is welcome.""")])])
581
582 def page_source_package(self, path, params, url):
583 pkg = path[0]
584
585 def gen_versions():
586 for (release, version) in self.db.getSourcePackageVersions(
587 self.db.cursor(), pkg):
588 yield release, version
589 def gen_bug_list(lst):
590 for (bug, description) in lst:
591 yield self.make_xref(url, bug), description
592
593 suites = ()
594 for (release, version) in self.db.getSourcePackageVersions(
595 self.db.cursor(), pkg):
596 if release not in suites:
597 suites = suites + (release,)
598
599 def gen_summary(bugs):
600 for (bug, description) in bugs:
601 status = {}
602 for (package, releases, version, vulnerable) \
603 in self.db.getSourcePackages(self.db.cursor(), bug):
604 for release in releases:
605 if package == pkg:
606 if vulnerable == 1:
607 status[release] = self.make_red('vulnerable')
608 elif vulnerable == 2:
609 status[release] = self.make_purple('undetermined')
610 else:
611 status[release] = self.make_green('fixed')
612 status_row = ()
613 for release in suites:
614 if release in status:
615 status_row = status_row + (status[release],)
616 else:
617 status_row = status_row + (self.make_purple('unknown'),)
618 yield (self.make_xref(url, bug),) + status_row + (description,)
619
620 return self.create_page(
621 url, 'Information on source package ' + pkg,
622 [make_menu(lambda x: x,
623 (self.url_pts(url, pkg),
624 pkg + ' in the Package Tracking System'),
625 (self.url_debian_bug_pkg(url, pkg),
626 pkg + ' in the Bug Tracking System'),
627 (self.url_source_code(url, pkg),
628 pkg + ' source code'),
629 (self.url_testing_status(url, pkg),
630 pkg + ' in the testing migration checker')),
631 make_table(gen_versions(), title=H2('Available versions'), caption=('Release', 'Version')),
632
633 make_table(
634 gen_summary(
635 # open issues
636 self.db.getBugsForSourcePackage(
637 self.db.cursor(), pkg, True, False),
638 ),
639 title=H2('Open issues'),
640 caption=('Bug',) + suites + ('Description',),
641 replacement='No known open issues.'
642 ),
643
644
645 make_table(
646 gen_summary(
647 # open unimportant isues
648 self.db.getBugsForSourcePackage(
649 self.db.cursor(), pkg, True, True),
650 ),
651 title=H2('Open unimportant issues'),
652 caption=('Bug',) + suites + ('Description',),
653 replacement='No known unimportant issues.'
654 ),
655
656 make_table(gen_bug_list(self.db.getBugsForSourcePackage
657 (self.db.cursor(), pkg, False, True)),
658 title=H2('Resolved issues'),
659 caption=('Bug', 'Description'),
660 replacement='No known resolved issues.'),
661
662 make_table(gen_bug_list(self.db.getDSAsForSourcePackage
663 (self.db.cursor(), pkg)),
664 title=H2('Security announcements'),
665 caption=('DSA / DLA', 'Description'),
666 replacement='No known security announcements.')
667 ])
668
669 def page_status_release_stable_oldstable_oldoldstable(self, release, params, url):
670 assert release in ('stable', 'oldstable', 'oldoldstable',)
671
672 bf = BugFilter(params)
673
674 def gen():
675 old_pkg_name = ''
676 for (pkg_name, bug_name, archive, urgency, vulnerable, remote, no_dsa) in \
677 self.db.cursor().execute(
678 """SELECT package, bug, section, urgency, vulnerable, remote, no_dsa
679 FROM %s_status
680 WHERE (bug LIKE 'CVE-%%' OR bug LIKE 'TEMP-%%')""" % release):
681 if bf.urgencyFiltered(urgency, vulnerable):
682 continue
683 if bf.remoteFiltered(remote):
684 continue
685 if bf.nodsaFiltered(no_dsa):
686 continue
687
688 if pkg_name == old_pkg_name:
689 pkg_name = ''
690 else:
691 old_pkg_name = pkg_name
692 title = None
693 if archive <> 'main':
694 title = "%s (%s)" % (pkg_name, archive)
695
696 if remote is None:
697 remote = '?'
698 elif remote:
699 remote = 'yes'
700 else:
701 remote = 'no'
702
703 if urgency.startswith('high'):
704 urgency = self.make_red(urgency)
705 elif vulnerable == 2:
706 urgency = self.make_purple(urgency)
707 else:
708 if no_dsa:
709 urgency = urgency + '*'
710
711 yield self.make_source_package_ref(url, pkg_name, title), self.make_xref(url, bug_name), urgency, remote
712
713 return self.create_page(
714 url, 'Vulnerable source packages in the %s suite' % release,
715 [bf.actions(url), BR(),
716 make_table(gen(), caption=("Package", "Bug", "Urgency", "Remote")),
717 P('''If a "*" is included in the urgency field, no DSA is planned
718 for this vulnerability.'''),
719 self.nvd_text])
720
721 def page_status_release_stable(self, path, params, url):
722 return self.page_status_release_stable_oldstable_oldoldstable('stable', params, url)
723 def page_status_release_oldstable(self, path, params, url):
724 return self.page_status_release_stable_oldstable_oldoldstable('oldstable',
725 params, url)
726 def page_status_release_oldoldstable(self, path, params, url):
727 return self.page_status_release_stable_oldstable_oldoldstable('oldoldstable',
728 params, url)
729
730 def page_status_release_testing(self, path, params, url):
731 bf = BugFilter(params)
732
733 def gen():
734 old_pkg_name = ''
735 for (pkg_name, bug_name, archive, urgency, vulnerable,
736 sid_vulnerable, ts_fixed, remote, no_dsa) \
737 in self.db.cursor().execute(
738 """SELECT package, bug, section, urgency, vulnerable,
739 unstable_vulnerable, testing_security_fixed, remote, no_dsa
740 FROM testing_status"""):
741 if bf.urgencyFiltered(urgency, vulnerable):
742 continue
743 if bf.remoteFiltered(remote):
744 continue
745 if bf.nodsaFiltered(no_dsa):
746 continue
747
748 if pkg_name == old_pkg_name:
749 pkg_name = ''
750 else:
751 old_pkg_name = pkg_name
752 title = None
753 if archive <> 'main':
754 title = "%s (%s)" % (pkg_name, archive)
755
756 if remote is None:
757 remote = '?'
758 elif remote:
759 remote = 'yes'
760 else:
761 remote = 'no'
762
763 if ts_fixed:
764 status = 'fixed in testing-security'
765 else:
766 if sid_vulnerable:
767 status = self.make_red('unstable is vulnerable')
768 else:
769 status = self.make_dangerous('fixed in unstable')
770
771 if urgency.startswith('high'):
772 urgency = self.make_red(urgency)
773 elif vulnerable == 2:
774 urgency = self.make_purple(urgency)
775
776 yield (self.make_source_package_ref(url, pkg_name, title), self.make_xref(url, bug_name),
777 urgency, remote, status)
778
779 return self.create_page(
780 url, 'Vulnerable source packages in the testing suite',
781 [make_menu(url.scriptRelative,
782 ("status/dtsa-candidates", "Candidates for DTSAs")),
783 bf.actions(url), BR(),
784 make_table(gen(), caption=("Package", "Bug", "Urgency", "Remote", 'Status')),
785 self.nvd_text])
786
787 def page_status_release_unstable_like(self, path, params, url,
788 rel, title, subrel=""):
789 bf = BugFilter(params,nonodsa=True)
790
791 def gen():
792 old_pkg_name = ''
793 for (pkg_name, bug_name, section, urgency, vulnerable, remote) \
794 in self.db.cursor().execute(
795 """SELECT DISTINCT sp.name, st.bug_name,
796 sp.archive, st.urgency, st.vulnerable,
797 (SELECT range_remote FROM nvd_data
798 WHERE cve_name = st.bug_name)
799 FROM source_package_status AS st, source_packages AS sp
800 WHERE st.vulnerable AND sp.rowid = st.package
801 AND sp.release = ? AND sp.subrelease = ''
802 ORDER BY sp.name, st.bug_name""", (rel,)):
803 if bf.urgencyFiltered(urgency, vulnerable):
804 continue
805 if bf.remoteFiltered(remote):
806 continue
807
808 if pkg_name == old_pkg_name:
809 pkg_name = ''
810 else:
811 old_pkg_name = pkg_name
812 title = None
813 if section <> 'main':
814 title = "%s (%s)" % (pkg_name, section)
815
816 if remote is None:
817 remote = '?'
818 elif remote:
819 remote = 'yes'
820 else:
821 remote = 'no'
822
823 if urgency.startswith('high'):
824 urgency = self.make_red(urgency)
825 elif vulnerable == 2:
826 urgency = self.make_purple(urgency)
827
828 yield self.make_source_package_ref(url, pkg_name, title), self.make_xref(url, bug_name), urgency, remote
829
830 return self.create_page(
831 url, title,
832 [P("""Note that the list below is based on source packages.
833 This means that packages are not listed here once a new,
834 fixed source version has been uploaded to the archive, even
835 if there are still some vulnerable binary packages present
836 in the archive."""),
837 bf.actions(url), BR(),
838 make_table(gen(), caption=('Package', 'Bug', 'Urgency', 'Remote')),
839 self.nvd_text])
840
841 def page_status_release_unstable(self, path, params, url):
842 return self.page_status_release_unstable_like(
843 path, params, url,
844 title='Vulnerable source packages in the unstable suite',
845 rel='sid')
846
847 def page_status_release_stable_backports(self, path, params, url):
848 return self.page_status_release_unstable_like(
849 path, params, url,
850 title='Vulnerable source packages among backports for stable',
851 rel='jessie-backports')
852
853 def page_status_release_oldstable_backports(self, path, params, url):
854 return self.page_status_release_unstable_like(
855 path, params, url,
856 title='Vulnerable source packages among backports for oldstable',
857 rel='wheezy-backports')
858
859 def page_status_release_oldoldstable_backports(self, path, params, url):
860 return self.page_status_release_unstable_like(
861 path, params, url,
862 title='Vulnerable source packages among backports for oldoldstable',
863 rel='squeeze-backports')
864
865
866 def page_status_dtsa_candidates(self, path, params, url):
867 bf = BugFilter(params,nonodsa=True)
868
869 def gen():
870 old_pkg_name = ''
871 for (pkg_name, bug_name, archive, urgency, vulnerable,
872 stable_later, remote) \
873 in self.db.cursor().execute(
874 """SELECT package, bug, section, urgency, vulnerable,
875 (SELECT testing.version_id < stable.version_id
876 FROM source_packages AS testing, source_packages AS stable
877 WHERE testing.name = testing_status.package
878 AND testing.release = 'jessie'
879 AND testing.subrelease = ''
880 AND testing.archive = testing_status.section
881 AND stable.name = testing_status.package
882 AND stable.release = 'jessie'
883 AND stable.subrelease = 'security'
884 AND stable.archive = testing_status.section),
885 (SELECT range_remote FROM nvd_data
886 WHERE cve_name = bug)
887 FROM testing_status
888 WHERE (NOT unstable_vulnerable)
889 AND (NOT testing_security_fixed)"""):
890 if bf.urgencyFiltered(urgency, vulnerable):
891 continue
892 if bf.remoteFiltered(remote):
893 continue
894
895 if pkg_name == old_pkg_name:
896 pkg_name = ''
897 migration = ''
898 else:
899 old_pkg_name = pkg_name
900 title = None
901 migration = A(self.url_testing_status(url, pkg_name),
902 "check")
903 if archive <> 'main':
904 title = "%s (%s)" % (pkg_name, archive)
905
906 if remote is None:
907 remote = '?'
908 elif remote:
909 remote = 'yes'
910 else:
911 remote = 'no'
912
913 if urgency.startswith('high'):
914 urgency = self.make_red(urgency)
915 elif vulnerable == 2:
916 urgency = self.make_purple(urgency)
917
918 if stable_later:
919 notes = "(fixed in stable?)"
920 else:
921 notes = ''
922
923 yield (self.make_source_package_ref(url, pkg_name, title), migration, self.make_xref(url, bug_name),
924 urgency, remote, notes)
925
926 return self.create_page(
927 url, "Candidates for DTSAs",
928 [P("""The table below lists packages which are fixed
929 in unstable, but unfixed in testing. Use the testing migration
930 checker to find out why they have not entered testing yet."""),
931 make_menu(url.scriptRelative,
932 ("status/release/testing",
933 "List of vulnerable packages in testing")),
934 bf.actions(url), BR(),
935 make_table(gen(),
936 caption=("Package", "Migration", "Bug", "Urgency",
937 "Remote", ""))])
938
939 def page_status_todo(self, path, params, url):
940 hide_check = params.get('hide_check', False)
941 if hide_check:
942 flags = A(url.updateParamsDict({'hide_check' : None}),
943 'Show "check" TODOs')
944 else:
945 flags = A(url.updateParamsDict({'hide_check' : '1'}),
946 'Hide "check" TODOs')
947
948 def gen():
949 for (bug, description, note) in self.db.getTODOs(hide_check=hide_check):
950 yield self.make_xref(url, bug), description, note
951 return self.create_page(
952 url, 'Bugs with TODO items',
953 [P(flags), make_table(gen(), caption=('Bug', 'Description', 'Note'))])
954
955 def page_status_undetermined(self, path, params, url):
956 def gen():
957 outrel = []
958 old_bug = ''
959 old_pkg = ''
960 old_dsc = ''
961 last_displayed = ''
962 releases = ('sid', 'stretch', 'jessie', 'wheezy', 'squeeze')
963 for (pkg_name, bug_name, release, desc) in self.db.cursor().execute(
964 """SELECT DISTINCT sp.name, st.bug_name, sp.release,
965 bugs.description
966 FROM source_package_status AS st, source_packages AS sp, bugs
967 WHERE st.vulnerable == 2 AND sp.rowid = st.package
968 AND ( sp.release = ? OR sp.release = ? OR sp.release = ?
969 OR sp.release = ? OR sp.release = ? )
970 AND sp.subrelease = '' AND st.bug_name == bugs.name
971 ORDER BY sp.name, st.bug_name""", releases):
972
973 if old_bug == '':
974 old_bug = bug_name
975 old_pkg = pkg_name
976 old_dsc = desc
977 elif old_bug != bug_name:
978 if old_pkg == last_displayed:
979 to_display = ''
980 else:
981 to_display = old_pkg
982 yield to_display, self.make_xref(url, old_bug), old_dsc, ', '.join(outrel)
983 last_displayed = old_pkg
984 old_bug = bug_name
985 old_pkg = pkg_name
986 old_dsc = desc
987 outrel = []
988 outrel.append( release )
989 yield old_pkg, self.make_xref(url, old_bug), old_dsc, ', '.join(outrel)
990
991 return self.create_page(url, 'Packages that may be vulnerable but need to be checked (undetermined issues)',
992 [P("""This page lists packages that may or may not be affected
993 by known issues. This means that some additional work needs to
994 be done to determined whether the package is actually
995 vulnerable or not. This list is a good area for new
996 contributors to make quick and meaningful contributions."""),
997 make_table(gen(), caption=('Package', 'Bug', 'Description', 'Releases'))])
998
999 def page_status_unimportant(self, path, params, url):
1000 def gen():
1001 outrel = []
1002 old_bug = ''
1003 old_pkg = ''
1004 old_dsc = ''
1005 old_name = ''
1006 last_displayed = ''
1007 releases = ('sid', 'stretch', 'jessie', 'wheezy', 'squeeze')
1008 for (pkg_name, bug_name, release, desc) in self.db.cursor().execute(
1009 """SELECT DISTINCT sp.name, st.bug_name, sp.release,
1010 bugs.description
1011 FROM source_package_status AS st, source_packages AS sp, bugs
1012 WHERE st.vulnerable > 0 AND sp.rowid = st.package
1013 AND ( sp.release = ? OR sp.release = ? OR sp.release = ?
1014 OR sp.release = ? OR sp.release = ? ) AND st.urgency == 'unimportant'
1015 AND sp.subrelease = '' AND st.bug_name == bugs.name
1016 ORDER BY sp.name, st.bug_name""", releases):
1017
1018 if old_bug == '':
1019 old_bug = bug_name
1020 old_pkg = pkg_name
1021 old_dsc = desc
1022 elif old_bug != bug_name:
1023 if old_pkg == last_displayed:
1024 to_display = ''
1025 else:
1026 to_display = old_pkg
1027 yield to_display, self.make_xref(url, old_bug), old_dsc, ', '.join(outrel)
1028 last_displayed = old_pkg
1029 old_bug = bug_name
1030 old_pkg = pkg_name
1031 old_dsc = desc
1032 outrel = []
1033 outrel.append( release )
1034 yield old_pkg, self.make_xref(url, old_bug), old_dsc, ', '.join(outrel)
1035
1036 return self.create_page(url, 'Packages that have open unimportant issues',
1037 [P("""This page lists packages that are affected by issues
1038 that are considered unimportant from a security perspective.
1039 These issues are thought to be unexploitable or uneffective
1040 in most situations (for example, browser denial-of-services)."""),
1041 make_table(gen(), caption=('Package', 'Bug', 'Description', 'Releases'))])
1042
1043 def page_status_itp(self, path, params, url):
1044 def gen():
1045 old_pkg = ''
1046 for pkg, bugs, debian_bugs in self.db.getITPs(self.db.cursor()):
1047 if pkg == old_pkg:
1048 pkg = ''
1049 else:
1050 old_pkg = pkg
1051 yield (pkg, self.make_xref_list(url, bugs),
1052 self.make_debian_bug_list(url, debian_bugs))
1053 return self.create_page(
1054 url, "ITPs with potential security issues",
1055 [make_table(gen(), caption=("Package", "Issue", "Debian Bugs"),
1056 replacement="No ITP bugs are currently known.")])
1057
1058 def page_status_unreported(self, path, params, url):
1059 def gen():
1060 for (bug, packages) in self.db.getUnreportedVulnerabilities():
1061 pkgs = make_list([self.make_source_package_ref(url, pkg)
1062 for pkg in packages], ", ")
1063 yield self.make_xref(url, bug), pkgs
1064 return self.create_page(
1065 url, "Unfixed vulnerabilities in unstable without a filed bug",
1066 [P("""The list below contains vulnerabilities for which no matching
1067 Debian bug has been filed, and there is still an unfixed package in sid."""),
1068 make_table(gen(), caption=("Bug", "Packages"))])
1069
1070 def page_data_unknown_packages(self, path, params, url):
1071 def gen():
1072 for name, bugs in self.db.getUnknownPackages(self.db.cursor()):
1073 yield name, self.make_xref_list(url, bugs)
1074 return self.create_page(
1075 url, "Unknown packages",
1076 [P("""Sometimes, a package referenced in a bug report
1077 cannot be found in the database. This can be the result of a spelling
1078 error, or a historic entry refers to a
1079 package which is no longer in the archive."""),
1080 make_table(gen(), caption=("Package", "Bugs"),
1081 replacement="No unknown packages are referenced in the database.")])
1082
1083 def page_data_missing_epochs(self, path, params, url):
1084 def gen():
1085 old_bug = ''
1086 old_pkg = ''
1087 for bug, pkg, ver1, ver2 in self.db.cursor().execute(
1088 """SELECT DISTINCT bug_name, n.package,
1089 n.fixed_version, sp.version
1090 FROM package_notes AS n, source_packages AS sp
1091 WHERE n.package_kind = 'source'
1092 AND n.fixed_version NOT LIKE '%:%'
1093 AND n.fixed_version <> '0'
1094 AND n.bug_origin = ''
1095 AND sp.name = n.package
1096 AND sp.version LIKE '%:%'
1097 ORDER BY bug_name, package"""):
1098 if bug == old_bug:
1099 bug = ''
1100 else:
1101 old_bug = bug
1102 old_pkg = ''
1103 bug = self.make_xref(url, bug)
1104 if pkg == old_pkg:
1105 pkg = ''
1106 else:
1107 old_pkg = pkg
1108 pkg = self.make_source_package_ref(url, pkg)
1109 yield bug, pkg, ver1, ver2
1110
1111 return self.create_page(
1112 url, "Missing epochs in package versions",
1113 [make_table(gen(),
1114 caption=("Bug", "Package", "Version 1", "Version 2"),
1115 replacement="No source package version with missing epochs.")])
1116
1117 def page_data_latently_vulnerable(self, path, params, url):
1118 def gen():
1119 for pkg, bugs in self.db.cursor().execute(
1120 """SELECT package, string_set(bug_name)
1121 FROM package_notes AS p1
1122 WHERE release <> ''
1123 AND (bug_name LIKE 'CVE-%' OR bug_name LIKE 'TEMP-%')
1124 AND NOT EXISTS (SELECT 1 FROM package_notes AS p2
1125 WHERE p2.bug_name = p1.bug_name
1126 AND p2.package = p1.package
1127 AND release = '')
1128 AND EXISTS (SELECT 1 FROM source_packages
1129 WHERE name = p1.package AND release = 'sid')
1130 GROUP BY package
1131 ORDER BY package"""):
1132 pkg = self.make_source_package_ref(url, pkg)
1133 bugs = bugs.split(',')
1134 yield pkg, self.make_xref_list(url, bugs)
1135
1136 def gen_unimportant():
1137 for pkg, bugs in self.db.cursor().execute(
1138 """SELECT package, string_set(bug_name)
1139 FROM package_notes AS p1
1140 WHERE release <> ''
1141 AND urgency <> 'unimportant'
1142 AND (bug_name LIKE 'CVE-%' OR bug_name LIKE 'TEMP-%')
1143 AND EXISTS (SELECT 1 FROM package_notes AS p2
1144 WHERE p2.bug_name = p1.bug_name
1145 AND p2.package = p1.package
1146 AND release = '')
1147 AND NOT EXISTS (SELECT 1 FROM package_notes AS p2
1148 WHERE p2.bug_name = p1.bug_name
1149 AND p2.package = p1.package
1150 AND urgency <> 'unimportant'
1151 AND release = '')
1152 AND EXISTS (SELECT 1 FROM source_packages
1153 WHERE name = p1.package AND release = 'sid')
1154 GROUP BY package
1155 ORDER BY package"""):
1156 pkg = self.make_source_package_ref(url, pkg)
1157 bugs = bugs.split(',')
1158 yield pkg, self.make_xref_list(url, bugs)
1159
1160 return self.create_page(
1161 url, "Latently vulnerable packages in unstable",
1162 [P(
1163 """A package is latently vulnerable in unstable if it is vulnerable in
1164 any release, and there is no package note for the same vulnerability
1165 and package in unstable (and the package is still available in
1166 unstable, of course)."""),
1167 make_table(gen(),
1168 caption=("Package", "Bugs"),
1169 replacement="No latently vulnerable packages were found."),
1170 P(
1171 """The next table lists issues which are marked unimportant for
1172 unstable, but for which release-specific annotations exist which are
1173 not unimportant."""),
1174 make_table(gen_unimportant(),
1175 caption=("Package", "Bugs"),
1176 replacement=
1177 "No packages with unimportant latent vulnerabilities were found."),
1178 ])
1179
1180 def page_data_releases(self, path, params, url):
1181 def gen():
1182 for (rel, subrel, archive, sources, archs) \
1183 in self.db.availableReleases():
1184 if sources:
1185 sources = 'yes'
1186 else:
1187 sources = 'no'
1188 if 'source' in archs:
1189 archs.remove('source')
1190 yield rel, subrel, archive, sources, make_list(archs)
1191 return self.create_page(
1192 url, "Available releases",
1193 [P("""The security issue database is checked against
1194 the Debian releases listed in the table below."""),
1195 make_table(gen(),
1196 caption=("Release", "Subrelease", "Archive",
1197 "Sources", "Architectures"))])
1198
1199 def page_data_funny_versions(self, path, params, url):
1200 def gen():
1201 for name, release, archive, version, source_version \
1202 in self.db.getFunnyPackageVersions():
1203 yield name, release, archive, source_version, version
1204
1205 return self.create_page(
1206 url, "Version conflicts between source/binary packages",
1207 [P("""The table below lists source packages
1208 which have a binary package of the same name, but with a different
1209 version. This means that extra care is necessary to determine
1210 the version of a package which has been fixed. (Note that
1211 the bug tracker prefers source versions to binary versions
1212 in this case.)"""),
1213 make_table(gen(),
1214 caption=("Package",
1215 "Release",
1216 "Archive",
1217 "Source Version",
1218 "Binary Version")),
1219 P("""Technically speaking, these version numbering is fine,
1220 but it makes version-based bug tracking quite difficult for these packages."""),
1221 P("""There are many binary packages which are built from source
1222 packages with different version numbering schemes. However, as
1223 long as none of the binary packages carries the same name as the
1224 source package, most confusion is avoided or can be easily
1225 explained.""")])
1226
1227 def page_data_fake_names(self, path, params, url):
1228 def gen(v):
1229 for (bug, description) in self.db.getFakeBugs(vulnerability=v):
1230 yield self.make_xref(url, bug), description
1231 return self.create_page(
1232 url, "Automatically generated issue names",
1233 [P("""Some issues have not been assigned CVE names, but are still
1234 tracked by this database. In this case, the system automatically assigns
1235 a unique name. These names are not stable and can change when the database
1236 is updated, so they should not be used in external references."""),
1237 P('''The automatically generated names come in two flavors:
1238 the first kind starts with the string "''', CODE("TEMP-000000-"),
1239 '''". This means that no Debian bug has been assigned to this
1240 issue (or a bug has been created and is not recorded in this database).
1241 In the second kind of names, there is a Debian bug for the issue, and the "''',
1242 CODE("000000"), '''"part of the name is replaced with the
1243 Debian bug number.'''),
1244 make_table(gen(1),title=H2('With unfixed issues'), caption=("Bug", "Description")),
1245 make_table(gen(0),title=H2('The rest'), caption=("Bug", "Description")),
1246 ])
1247
1248 def page_data_pts(self, path, params, url):
1249 data = []
1250 for pkg, bugs in self.db.cursor().execute(
1251 """SELECT package, COUNT(DISTINCT bug) FROM
1252 (SELECT package, bug, urgency FROM stable_status
1253 UNION ALL SELECT DISTINCT sp.name, st.bug_name, st.urgency
1254 FROM source_package_status AS st, source_packages AS sp
1255 WHERE st.vulnerable AND st.urgency <> 'unimportant'
1256 AND sp.rowid = st.package AND sp.release = 'sid'
1257 AND sp.subrelease = '') x WHERE urgency <> 'unimportant'
1258 GROUP BY package ORDER BY package"""):
1259 data.append(pkg)
1260 data.append(':')
1261 data.append(str(bugs))
1262 data.append('\n')
1263 return BinaryResult(''.join(data),'application/octet-stream')
1264
1265 def page_json(self, path, params, url):
1266
1267 from collections import defaultdict
1268 packages = []
1269 issues = defaultdict(list)
1270 descriptions = {}
1271 debianbugs = defaultdict(dict)
1272 remote = defaultdict(dict)
1273 releases = defaultdict(lambda: defaultdict(list))
1274 subreleases = defaultdict(lambda: defaultdict(list))
1275 repositories = defaultdict(lambda: defaultdict(list))
1276 version = defaultdict(lambda: defaultdict(dict))
1277 fixed_version = defaultdict(lambda: defaultdict(dict))
1278 status = defaultdict(lambda: defaultdict(dict))
1279 urgency = defaultdict(lambda: defaultdict(dict))
1280 nodsa = defaultdict(lambda: defaultdict(dict))
1281 supported_releases = ('sid', 'stretch', 'jessie', 'wheezy', 'squeeze')
1282 for (pkg, issue, desc, debianbug, release, subrelease, db_version, db_fixed_version, db_status, db_urgency, db_remote, db_nodsa) in self.db.cursor().execute(
1283 """SELECT sp.name, st.bug_name,
1284 (SELECT cve_desc FROM nvd_data
1285 WHERE cve_name = st.bug_name),
1286 (SELECT debian_cve.bug FROM debian_cve
1287 WHERE debian_cve.bug_name = st.bug_name
1288 ORDER BY debian_cve.bug),
1289 sp.release, sp.subrelease,
1290 sp.version,
1291 (SELECT pn.fixed_version FROM package_notes AS pn
1292 WHERE pn.bug_name = st.bug_name
1293 AND pn.package = sp.name AND
1294 (pn.release = sp.release OR (pn.release = '' AND fixed_version != ''))),
1295 st.vulnerable, st.urgency,
1296 (SELECT range_remote FROM nvd_data
1297 WHERE cve_name = st.bug_name),
1298 (SELECT comment FROM package_notes_nodsa AS nd
1299 WHERE nd.package = sp.name AND nd.release = sp.release
1300 AND nd.bug_name = st.bug_name) AS nodsa
1301 FROM source_package_status AS st, source_packages AS sp, bugs
1302 WHERE sp.rowid = st.package AND st.bug_name = bugs.name
1303 AND ( sp.release = ? OR sp.release = ? OR sp.release = ?
1304 OR sp.release = ? OR sp.release = ? )
1305 ORDER BY sp.name, st.bug_name, sp.release, sp.subrelease""" , supported_releases):
1306
1307 ### to ease debugging...:
1308 #if issue in ('CVE-2012-6656','CVE-2014-8738','CVE-2013-6673') :
1309 # print pkg, issue, release, subrelease, db_version, db_fixed_version, db_status
1310 if pkg not in packages:
1311 packages.append(pkg)
1312 if issue not in issues[pkg]:
1313 issues[pkg].append(issue)
1314 descriptions[issue] = desc
1315 debianbugs[pkg][issue] = debianbug
1316 remote[pkg][issue] = db_remote
1317 if release not in releases[pkg][issue]:
1318 releases[pkg][issue].append(release)
1319 subreleases[pkg][issue].append(subrelease)
1320 if subrelease == '':
1321 repository = release
1322 else:
1323 repository = release+'-'+subrelease
1324 if repository not in repositories[pkg][issue]:
1325 repositories[pkg][issue].append(repository)
1326 version[pkg][issue][repository] = db_version
1327 fixed_version[pkg][issue][repository] = db_fixed_version
1328 status[pkg][issue][repository] = db_status
1329 urgency[pkg][issue][repository] = db_urgency
1330 if str(db_nodsa) != 'None':
1331 nodsa[pkg][issue][repository] = db_nodsa
1332
1333 data = {}
1334 for pkg in packages:
1335 data[pkg] = {}
1336 for issue in issues[pkg]:
1337 description = None
1338 debianbug = None
1339 scope = None
1340 suites = {}
1341
1342 if descriptions[issue]:
1343 description = descriptions[issue]
1344 if debianbugs[pkg][issue] != None:
1345 debianbug = debianbugs[pkg][issue]
1346 if str(remote[pkg][issue]) == 'None':
1347 pass
1348 elif remote[pkg][issue] == 1:
1349 scope = "remote"
1350 else:
1351 scope = "local"
1352 for release in releases[pkg][issue]:
1353 state = None
1354 suite_fixed_version = None
1355 suite_urgency = None
1356 suite_nodsa = None
1357 suite_repositories = {}
1358 winner=''
1359 for suffix in ('','-security','-lts'):
1360 subrelease=release+suffix
1361 if status[pkg][issue].has_key(subrelease):
1362 if status[pkg][issue][subrelease] == 0:
1363 # the issue is fixed, let's pick this subrelease and be done
1364 winner=suffix
1365 break
1366 elif status[pkg][issue][subrelease] > 0 and winner == '':
1367 # the issue ain't fixed, but at least exists.
1368 # keep looking for a real winner...
1369 winner=suffix
1370 repository=release+winner
1371 if status[pkg][issue][repository] == 0:
1372 # 1 = vulnerable, 2 = undetermined
1373 state = "resolved"
1374 suite_fixed_version = fixed_version[pkg][issue][repository]
1375 elif status[pkg][issue][repository] == 2:
1376 state = "undetermined"
1377 else:
1378 state = "open"
1379 suite_urgency = urgency[pkg][issue][repository]
1380 if nodsa[pkg][issue].has_key(repository):
1381 suite_nodsa = nodsa[pkg][issue][repository]
1382 for repository in repositories[pkg][issue]:
1383 for suffix in ('','-security','-lts'):
1384 subrelease=release+suffix
1385 if version[pkg][issue].has_key(subrelease):
1386 suite_repositories[subrelease] = version[pkg][issue][subrelease]
1387 suites[release] = { "status": state,
1388 "repositories": suite_repositories,
1389 "fixed_version" : suite_fixed_version,
1390 "urgency": suite_urgency,
1391 "nodsa": suite_nodsa }
1392 clean_dict(suites[release])
1393 pkg_issue = { "description": description,
1394 "debianbug": debianbug,
1395 "scope": scope,
1396 "releases": suites }
1397 clean_dict(pkg_issue)
1398
1399 data[pkg][issue]=pkg_issue
1400
1401 json_data = json.dumps(data, sort_keys=True, indent=True)
1402 return BinaryResult(json_data,'application/octet-stream')
1403
1404 def page_debsecan(self, path, params, url):
1405 obj = '/'.join(path)
1406 data = self.db.getDebsecan(obj)
1407 if data:
1408 return BinaryResult(data,'application/octet-stream')
1409 else:
1410 return self.create_page(
1411 url, "Object not found",
1412 [P("The requested debsecan object has not been found.")],
1413 status=404)
1414
1415 def create_page(self, url, title, body, search_in_page=False, status=200):
1416 append = body.append
1417 append(HR())
1418 if not search_in_page:
1419 append(self.make_search_button(url))
1420 append(FOOTER(P(A(url.scriptRelative(""), "Home"),
1421 " - ", A(url.absolute("https://www.debian.org/security/"),
1422 "Debian Security"),
1423 " - ", A(url.absolute("https://anonscm.debian.org/viewvc/secure-testing/bin/tracker_service.py?view=markup"),
1424 "Source"),
1425 " ", A(url.absolute("svn://anonscm.debian.org/svn/secure-testing"), "(SVN)"),
1426 )))
1427 if search_in_page:
1428 on_load = "selectSearch()"
1429 else:
1430 on_load = None
1431 return HTMLResult(self.add_title(title, body,
1432 head_contents=self.head_contents,
1433 body_attribs={'onload': on_load}),
1434 doctype=self.html_dtd(),
1435 status=status)
1436
1437 def make_search_button(self, url):
1438 return FORM("Search for package or bug name: ",
1439 INPUT(type='text', name='query',
1440 onkeyup="onSearch(this.value)",
1441 onmousemove="onSearch(this.value)"),
1442 INPUT(type='submit', value='Go'),
1443 ' ',
1444 A(url.scriptRelative("data/report"), "Reporting problems"),
1445 method='get',
1446 id='searchform',
1447 action=url.scriptRelative(''))
1448
1449 def url_cve(self, url, name):
1450 return url.absolute("https://cve.mitre.org/cgi-bin/cvename.cgi",
1451 name=name)
1452 def url_nvd(self, url, name):
1453 return url.absolute("https://web.nvd.nist.gov/view/vuln/detail",
1454 vulnId=name)
1455 def url_osssec_bug(self, url, name):
1456 return url.absolute("https://marc.info/", l="oss-security", s=name)
1457 def url_fulldesc_bug(self, url, name):
1458 return url.absolute("https://marc.info/", l="full-disclosure", s=name)
1459 def url_osvdb_bug(self, url, name):
1460 return url.absoluteDict("http://osvdb.org/search/search", {"search[refid]": name})
1461 def url_edb_bug(self, url, name):
1462 name = name[len('CVE-'):] if name.startswith('CVE-') else name
1463 return url.absolute("http://www.exploit-db.com/search/", action="search", cve=name)
1464 def url_metasploit_bug(self, url, name):
1465 return url.absolute("https://www.rapid7.com/db/search", q=name)
1466 def url_rhbug(self, url, name):
1467 return url.absolute("https://bugzilla.redhat.com/show_bug.cgi",
1468 id=name)
1469 def url_ubuntu_bug(self, url, name):
1470 return url.absolute("http://people.canonical.com/~ubuntu-security/cve/%s" % name)
1471 def url_gentoo_bug(self, url, name):
1472 return url.absolute("https://bugs.gentoo.org/show_bug.cgi", id=name)
1473 def url_suse_bug(self, url, name):
1474 return url.absolute("https://bugzilla.novell.com/show_bug.cgi",
1475 id=name)
1476 def url_mageia_bug(self, url, name):
1477 return url.absolute("https://advisories.mageia.org/%s.html" % name)
1478
1479 def url_dsa(self, url, dsa, re_dsa=re.compile(r'^DSA-(\d+)(?:-\d+)?$')):
1480 match = re_dsa.match(dsa)
1481 if match:
1482 # We must determine the year because there is no generic URL.
1483 (number,) = match.groups()
1484 for (date,) in self.db.cursor().execute(
1485 "SELECT release_date FROM bugs WHERE name = ?", (dsa,)):
1486 (y, m, d) = date.split('-')
1487 return url.absolute("https://www.debian.org/security/%d/dsa-%d"
1488 % (int(y), int(number)))
1489 return None
1490
1491 def url_debian_bug(self, url, debian):
1492 return url.absolute("https://bugs.debian.org/cgi-bin/bugreport.cgi",
1493 bug=str(debian))
1494 def url_debian_bug_pkg(self, url, debian):
1495 return url.absolute("https://bugs.debian.org/cgi-bin/pkgreport.cgi",
1496 pkg=debian)
1497 def url_source_code(self, url, package):
1498 return url.absolute("https://sources.debian.net/src/%s/" % package)
1499 def url_pts(self, url, package):
1500 return url.absolute("https://tracker.debian.org/pkg/%s" % package)
1501 def url_testing_status(self, url, package):
1502 return url.absolute("https://release.debian.org/migration/testing.pl",
1503 package=package)
1504 def url_source_package(self, url, package, full=False):
1505 if full:
1506 return url.scriptRelativeFull("source-package/" + package)
1507 else:
1508 return url.scriptRelative("source-package/" + package)
1509
1510 def make_xref(self, url, name):
1511 return A(url.scriptRelative(name), name)
1512
1513 def make_xref_list(self, url, lst, separator=', '):
1514 return make_list(map(lambda x: self.make_xref(url, x), lst), separator)
1515
1516 def make_debian_bug(self, url, debian):
1517 return A(self.url_debian_bug(url, debian), str(debian))
1518 def make_debian_bug_list(self, url, lst):
1519 return make_list(map(lambda x: self.make_debian_bug(url, x), lst))
1520
1521 def make_cve_ref(self, url, cve, name=None):
1522 if name is None:
1523 name = cve
1524 return A(self.url_cve(url, cve), name)
1525
1526 def make_nvd_ref(self, url, cve, name=None):
1527 if name is None:
1528 name = cve
1529 return A(self.url_nvd(url, cve), name)
1530
1531 def make_osssec_bug_ref(self, url, cve, name=None):
1532 if name is None:
1533 name = cve
1534 return A(self.url_osssec_bug(url, cve), name)
1535
1536 def make_fulldisc_bug_ref(self, url, cve, name=None):
1537 if name is None:
1538 name = cve
1539 return A(self.url_fulldesc_bug(url, cve), name)
1540
1541 def make_osvdb_bug_ref(self, url, cve, name=None):
1542 if name is None:
1543 name = cve
1544 return A(self.url_osvdb_bug(url, cve), name)
1545
1546 def make_edb_bug_ref(self, url, cve, name=None):
1547 if name is None:
1548 name = cve
1549 return A(self.url_edb_bug(url, cve), name)
1550
1551 def make_metasploit_bug_ref(self, url, cve, name=None):
1552 if name is None:
1553 name = cve
1554 return A(self.url_metasploit_bug(url, cve), name)
1555
1556 def make_rhbug_ref(self, url, cve, name=None):
1557 if name is None:
1558 name = cve
1559 return A(self.url_rhbug(url, cve), name)
1560
1561 def make_ubuntu_bug_ref(self, url, cve, name=None):
1562 if name is None:
1563 name = cve
1564 return A(self.url_ubuntu_bug(url, cve), name)
1565
1566 def make_gentoo_bug_ref(self, url, cve, name=None):
1567 if name is None:
1568 name = cve
1569 return A(self.url_gentoo_bug(url, cve), name)
1570
1571 def make_suse_bug_ref(self, url, cve, name=None):
1572 if name is None:
1573 name = cve
1574 return A(self.url_suse_bug(url, cve), name)
1575
1576 def make_mageia_bug_ref(self, url, cve, name=None):
1577 if name is None:
1578 name = cve
1579 return A(self.url_mageia_bug(url, cve), name)
1580
1581 def make_dsa_ref(self, url, dsa, name=None):
1582 if name is None:
1583 name = dsa
1584 u = self.url_dsa(url, dsa)
1585 if u:
1586 return A(u, name)
1587 else:
1588 return name
1589
1590 def make_source_code_ref(self, url, pkg, name=None):
1591 if name is None:
1592 name = pkg
1593 return A(self.url_source_code(url, pkg), name)
1594
1595 def make_pts_ref(self, url, pkg, name=None):
1596 if name is None:
1597 name = pkg
1598 return A(self.url_pts(url, pkg), name)
1599
1600 def make_source_package_ref(self, url, pkg, title=None):
1601 if title is None:
1602 title = pkg
1603 return A(self.url_source_package(url, pkg), title)
1604
1605 def make_red(self, contents):
1606 return SPAN(contents, _class="red")
1607
1608 def make_purple(self, contents):
1609 return SPAN(contents, _class="purple")
1610
1611 def make_green(self, contents):
1612 return SPAN(contents, _class="green")
1613
1614 def make_dangerous(self, contents):
1615 return SPAN(contents, _class="dangerous")
1616
1617 def pre_dispatch(self):
1618 pass
1619
1620 TrackerService(socket_name, db_name).run()

Properties

Name Value
svn:mime-type text/script

  ViewVC Help
Powered by ViewVC 1.1.5