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

Contents of /bin/tracker_service.py

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:mime-type text/script

  ViewVC Help
Powered by ViewVC 1.1.5