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

Contents of /bin/tracker_service.py

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:mime-type text/script

  ViewVC Help
Powered by ViewVC 1.1.5