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

Contents of /bin/tracker_service.py

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:mime-type text/script

  ViewVC Help
Powered by ViewVC 1.1.5