1 /*-
2 * Copyright (c) 2004 Jacques A. Vidrine
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 */
27 #include <sys/param.h>
28
29 #include <algorithm>
30 #include <iostream>
31 #include <fstream>
32 #include <map>
33 #include <string>
34 #include <utility>
35 #include <vector>
36
37 #include <vuxml/vuxml.hh>
38 #include <vuxml/constants.hh>
39 #include <vuxml/processors.hh>
40
41
42 using namespace vuxml;
43
44
45 //
46 // AllMatcher
47 //
AllMatcher(EntryProcessor & proc)48 AllMatcher::AllMatcher(EntryProcessor &proc) : proc_(proc) {}
49
50
51 bool
operator ()(const Entry & entry)52 AllMatcher::operator()(const Entry &entry)
53 {
54 return proc_(entry);
55 }
56
57
start()58 void AllMatcher::start() { proc_.start(); }
end()59 void AllMatcher::end() { proc_.end(); }
60
61
62 //
63 // VersionMatcher
64 //
VersionMatcher(std::vector<std::string> & args,EntryProcessor & proc)65 VersionMatcher::VersionMatcher(std::vector<std::string> &args, EntryProcessor &proc) :
66 args_(args), proc_(proc)
67 {
68 }
69
70
71 bool
operator ()(const Entry & entry)72 VersionMatcher::operator()(const Entry &entry)
73 {
74 std::vector<std::string>::const_iterator arg, arg_end;
75 std::vector<std::string>::const_iterator nam, nam_end;
76 std::vector<AffectedSet>::const_iterator aff, aff_end;
77 std::vector<VersionRange>::const_iterator rng, rng_end;
78 std::string name, version;
79 std::string::size_type i, npos = std::string::npos;
80
81 for (arg = args_.begin(), arg_end = args_.end();
82 arg != arg_end; ++arg) {
83 i = arg->rfind('-');
84 if (i == npos) {
85 name = *arg;
86 version = VersionRange::zero;
87 } else {
88 name = arg->substr(0, i);
89 version = arg->substr(i+1, npos);
90 }
91 for (aff = entry.affected().begin(),
92 aff_end = entry.affected().end(); aff != aff_end; ++aff) {
93 for (nam = aff->names.begin(),
94 nam_end = aff->names.end();
95 nam != nam_end; ++nam) {
96 if (*nam == name)
97 break;
98 }
99 if (nam == nam_end)
100 continue;
101 for (rng = aff->ranges.begin(),
102 rng_end = aff->ranges.end(); rng != rng_end; ++rng)
103 if (rng->contains(version))
104 return proc_(entry);
105 }
106 }
107 return true;
108 }
109
110
start()111 void VersionMatcher::start() { proc_.start(); }
end()112 void VersionMatcher::end() { proc_.end(); }
113
114
115 //
116 // TextWriter
117 //
TextWriter(std::ostream & os)118 TextWriter::TextWriter(std::ostream &os) : os_(os)
119 {
120 }
121
122
123 namespace {
124 void
writeTopic(std::ostream & os,const Entry & entry)125 writeTopic(std::ostream &os, const Entry &entry)
126 {
127 os << "Topic: " << entry.topic() << '\n';
128 }
129
130
131 void
writeRangeExpression(std::ostream & os,const std::string & nam,const VersionRange & rng)132 writeRangeExpression(std::ostream &os, const std::string &nam,
133 const VersionRange &rng)
134 {
135 os << " ";
136 if (rng.lo == rng.hi)
137 os << nam << " == " << rng.lo;
138 else if (rng.lo != VersionRange::zero && rng.hi != VersionRange::infinity)
139 os << rng.lo << " <" << (rng.lo_closed ? "=" : "") << ' '
140 << nam << " <" << (rng.hi_closed ? "=" : "") << ' '
141 << rng.hi;
142 else if (rng.hi != VersionRange::infinity)
143 os << nam << " <" << (rng.hi_closed ? "=" : "") << ' '
144 << rng.hi;
145 else
146 os << rng.lo << " <" << (rng.lo_closed ? "=" : "") << ' '
147 << nam;
148 os << '\n';
149 }
150
151
152 void
writeAffected(std::ostream & os,const Entry & entry)153 writeAffected(std::ostream &os, const Entry &entry)
154 {
155 std::vector<AffectedSet>::const_iterator aff, aff_end;
156 std::vector<VersionRange>::const_iterator rng, rng_end;
157 std::vector<std::string>::const_iterator nam, nam_end;
158
159 os << "Affects:\n";
160 aff_end = entry.affected().end();
161 for (aff = entry.affected().begin(); aff != aff_end; ++aff) {
162 nam_end = aff->names.end();
163 for (nam = aff->names.begin(); nam != nam_end; ++nam) {
164 rng_end = aff->ranges.end();
165 for (rng = aff->ranges.begin(); rng != rng_end;
166 ++rng)
167 writeRangeExpression(os, *nam, *rng);
168 }
169 }
170 }
171
172
173 void
writeReferences(std::ostream & os,const Entry & entry)174 writeReferences(std::ostream &os, const Entry &entry)
175 {
176 std::vector<Reference>::const_iterator ref, ref_end;
177
178 os << "References:\n";
179 ref_end = entry.references().end();
180 for (ref = entry.references().begin(); ref != ref_end; ++ref)
181 os << " " << ref->type << ':' << ref->text << '\n';
182 }
183 }
184
185
186
187 bool
operator ()(const Entry & entry)188 TextWriter::operator()(const Entry &entry)
189 {
190 writeTopic(os_, entry);
191 writeAffected(os_, entry);
192 writeReferences(os_, entry);
193 os_ << "<URL:http://vuxml.freebsd.org/"
194 << entry.vid() << ".html>\n\n";
195 return true;
196 }
197
198
199 //
200 // VuXMLWriter
201 //
VuXMLWriter(std::ostream & os)202 VuXMLWriter::VuXMLWriter(std::ostream &os) : os_(os) {}
203
204
205 void
start()206 VuXMLWriter::start()
207 {
208 os_ << "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
209 << "<!DOCTYPE vuxml PUBLIC \"-//vuxml.org//DTD VuXML 1.0//EN\"\n"
210 << " \"http://www.vuxml.org/dtd/vuxml-1/vuxml-10.dtd\">\n"
211 << "<vuxml xmlns=\"http://www.vuxml.org/apps/vuxml-1\">\n";
212 }
213
214
215 void
end()216 VuXMLWriter::end()
217 {
218 os_ << "</vuxml>\n";
219 }
220
221
222 namespace vuxml { namespace vuxmlwriter {
223
224 struct WriteAffected : public std::unary_function<void, const AffectedSet &> {
225 std::ostream &os_;
WriteAffectedvuxml::vuxmlwriter::WriteAffected226 WriteAffected(std::ostream &os) : os_(os) {}
operator ()vuxml::vuxmlwriter::WriteAffected227 void operator()(const AffectedSet &as) {
228 os_ << " <package>\n";
229
230 std::vector<std::string>::const_iterator nam, nam_end;
231 for (nam = as.names.begin(), nam_end = as.names.end();
232 nam != nam_end; ++nam)
233 os_ << " <name>" << xmlescape(*nam) << "</name>\n";
234
235 std::vector<VersionRange>::const_iterator rng, rng_end;
236 std::string hi, lo;
237 for (rng = as.ranges.begin(), rng_end = as.ranges.end();
238 rng != rng_end; ++rng) {
239 hi = xmlescape(rng->hi);
240 lo = xmlescape(rng->lo);
241 os_ << " <range>";
242 if (rng->lo == rng->hi) {
243 os_ << "<eq>" << rng->lo << "</eq>";
244 continue;
245 }
246 if (rng->lo != VersionRange::zero)
247 os_ << (rng->lo_closed? "<ge>": "<gt>") << lo
248 << (rng->lo_closed?"</ge>":"</gt>");
249 if (rng->hi != VersionRange::infinity)
250 os_ << (rng->hi_closed? "<le>": "<lt>") << hi
251 << (rng->hi_closed?"</le>":"</lt>");
252 os_ << "</range>\n";
253 }
254
255 os_ << " </package>\n";
256 }
257 };
258
259
260 struct WriteReferences : public std::unary_function<void, const Reference &> {
261 std::ostream &os_;
WriteReferencesvuxml::vuxmlwriter::WriteReferences262 WriteReferences(std::ostream &os) : os_(os) {}
operator ()vuxml::vuxmlwriter::WriteReferences263 void operator()(const Reference &ref) {
264 os_ << " <" << ref.type << ">"
265 << xmlescape(ref.text) << "</" << ref.type << ">\n";
266 }
267 };
268 }}
269
270
271 bool
operator ()(const Entry & entry)272 VuXMLWriter::operator()(const Entry &entry)
273 {
274 using namespace vuxml::vuxmlwriter;
275 os_ << " <vuln vid=\"" << xmlescape(entry.vid()) << "\">\n"
276 << " <topic>" << xmlescape(entry.topic()) << "</topic>\n"
277 << " <affects>\n";
278 std::for_each(entry.affected().begin(), entry.affected().end(),
279 WriteAffected(os_));
280 os_ << " </affects>\n"
281 << " <description>\n"
282 << " <body xmlns=\"" << XHTML_NAMESPACE << "\">\n"
283 << entry.description()
284 << " </body>\n"
285 << " </description>\n"
286 << " <references>\n";
287 std::for_each(entry.references().begin(), entry.references().end(),
288 WriteReferences(os_));
289 os_ << " </references>\n"
290 << " <dates>\n"
291 << " <discovery>" << xmlescape(entry.discoveryDate())
292 << "</discovery>\n"
293 << " <entry>" << xmlescape(entry.entryDate())
294 << "</entry>\n";
295 if (entry.modifiedDate().size() != 0)
296 os_ << " <modified>" << xmlescape(entry.modifiedDate())
297 << "</modified>\n";
298 os_ << " </dates>\n"
299 << " </vuln>\n";
300 return true;
301 }
302
303
304 //
305 // XHTMLWriter
306 //
XHTMLWriter(std::ostream & os,unsigned int h1)307 XHTMLWriter::XHTMLWriter(std::ostream &os, unsigned int h1) :
308 os_(os), h1_(h1) {}
309
310
311 void
start()312 XHTMLWriter::start()
313 {
314 os_ << "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
315 << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML Basic 1.0//EN\"\n"
316 << " \"http://www.w3.org/TR/xhtml-basic/xhtml-basic10.dtd\">\n"
317 << "<html>\n"
318 << " <head><title>vxquery report</title></head>\n"
319 << " <body><h1>vxquery report</h1>\n";
320 }
321
322
323 void
end()324 XHTMLWriter::end()
325 {
326 os_ << "</body></html>\n";
327 }
328
329
330 namespace vuxml { namespace xhtmlwriter {
331 struct WriteRangeExpression : public std::binary_function<void,
332 const std::string &, const VersionRange &> {
333 std::ostream &os_;
WriteRangeExpressionvuxml::xhtmlwriter::WriteRangeExpression334 WriteRangeExpression(std::ostream &os) : os_(os) {}
operator ()vuxml::xhtmlwriter::WriteRangeExpression335 void operator()(const std::string &nam, const VersionRange &rng) {
336 std::string s;
337 if (rng.lo == rng.hi) {
338 s += nam; s += " == "; s += rng.lo;
339 } else if (rng.hi != VersionRange::infinity &&
340 rng.lo == VersionRange::zero) {
341 s += nam; s += " <";
342 if (rng.hi_closed) s += "=";
343 s += " "; s += rng.hi;
344 } else {
345 s += rng.lo; s += " <";
346 if (rng.lo_closed) s += "=";
347 s += " "; s += nam;
348 if (rng.hi != VersionRange::infinity) {
349 s += " <";
350 if (rng.hi_closed) s += "=";
351 s += " "; s += rng.hi;
352 }
353 }
354 os_ << xmlescape(s) << "<br/>";
355 }
356 };
357
358
359 struct WriteAffected : public std::unary_function<void, const AffectedSet &> {
360 std::ostream &os_;
WriteAffectedvuxml::xhtmlwriter::WriteAffected361 WriteAffected(std::ostream &os) : os_(os) {}
operator ()vuxml::xhtmlwriter::WriteAffected362 void operator()(const AffectedSet &as) {
363 std::vector<VersionRange>::const_iterator rng, rng_end;
364 std::vector<std::string>::const_iterator nam, nam_end;
365 WriteRangeExpression fn(os_);
366
367 os_ << "<p>";
368 for (nam = as.names.begin(), nam_end = as.names.end() ; nam != nam_end;
369 ++nam)
370 for (rng = as.ranges.begin(), rng_end = as.ranges.end();
371 rng != rng_end; ++rng)
372 fn(*nam, *rng);
373 os_ << "</p>\n";
374 }
375 };
376
377
378 struct WriteReferences : public std::unary_function<void, const Reference &> {
379 std::ostream &os_;
WriteReferencesvuxml::xhtmlwriter::WriteReferences380 WriteReferences(std::ostream &os) : os_(os) {}
operator ()vuxml::xhtmlwriter::WriteReferences381 void operator()(const Reference &ref) {
382 std::string link, tmp = xmlescape(ref.text);
383 if (ref.type == "url") {
384 os_ << "<tr><td>URL</td><td><a href=\""
385 << tmp << "\">" << tmp << "</a></td></tr>\n";
386 } else if (ref.type == "cvename") {
387 link = "http://cve.mitre.org/cgi-bin/cvename.cgi?name=";
388 link += tmp;
389 os_ << "<tr><td>CVE Name</td><td><a href=\""
390 << link << "\">" << tmp << "</a></td></tr>\n";
391 } else if (ref.type == "bid") {
392 link = "http://www.securityfocus.com/bid/";
393 link += tmp;
394 os_ << "<tr><td>Bugtraq ID</td><td><a href=\""
395 << link << "\">" << tmp << "</a></td></tr>\n";
396 } else if (ref.type == "certsa") {
397 link = "http://www.cert.org/advisories/";
398 link += tmp;
399 link += ".html";
400 os_ << "<tr><td>CERT/CC Advisory</td><td><a href=\""
401 << link << "\">" << tmp << "</a></td></tr>\n";
402 } else if (ref.type == "certvu") {
403 link = "http://www.kb.cert.org/vuls/id/";
404 link += tmp;
405 os_ << "<tr><td>CERT/CC Vulnerability Note</td><td><a href=\""
406 << link << "\">" << tmp << "</a></td></tr>\n";
407 } else if (ref.type == "freebsdsa") {
408 link = "ftp://ftp.freebsd.org/pub/CERT/advisories/FreeBSD-";
409 link += tmp;
410 link += ".asc";
411 os_ << "<tr><td>FreeBSD Advisory</td><td><a href=\""
412 << link << "\">" << tmp << "</a></td></tr>\n";
413 } else {
414 os_ << "<tr><td>" << xmlescape(ref.type)
415 << "</td><td>" << xmlescape(ref.text) << "</td></tr>\n";
416 }
417 }
418 };
419 }}
420
421
422 bool
operator ()(const Entry & entry)423 XHTMLWriter::operator()(const Entry &entry)
424 {
425 using namespace vuxml::xhtmlwriter;
426 os_ << "<h" << h1_+1 << " id=\"_" << xmlescape(entry.vid()) << "\">"
427 << xmlescape(entry.topic()) << "</h" << h1_+1 << ">\n"
428 << "<h" << h1_+2 << ">Affects</h" << h1_+2 << ">\n";
429 std::for_each(entry.affected().begin(), entry.affected().end(),
430 WriteAffected(os_));
431 os_ << "<h" << h1_+2 << ">Description</h" << h1_+2 << ">\n"
432 << entry.description() << '\n'
433 << "<h" << h1_+2 << ">References</h" << h1_+2 << ">\n"
434 << "<table>\n";
435 std::for_each(entry.references().begin(), entry.references().end(),
436 WriteReferences(os_));
437
438 os_ << "</table>\n";
439 return true;
440 }
441
442
443 //
444 // XHTMLFilesWriter
445 //
446
447
XHTMLFilesWriter(const std::string & dir)448 XHTMLFilesWriter::XHTMLFilesWriter(const std::string &dir) : dir_(dir), fails_(0) {}
449
450
451 bool
operator ()(const Entry & entry)452 XHTMLFilesWriter::operator()(const Entry &entry)
453 {
454 std::string path = dir_; path += "/"; path += entry.vid(); path += ".html";
455
456 std::ofstream ofs;
457 ofs.open(path.c_str(), std::ofstream::binary |
458 std::ofstream::out | std::ofstream::trunc);
459
460 if (ofs.fail()) {
461 ++fails_;
462 if (fails_ > 10)
463 throw except("Too many failures.");
464 LOG << "Warning: cannot open file `" << path << "'\n"
465 << "for output.\n";
466 return false;
467 }
468
469
470 ofs << "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
471 << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML Basic 1.0//EN\"\n"
472 << " \"http://www.w3.org/TR/xhtml-basic/xhtml-basic10.dtd\">\n"
473 << "<html>\n"
474 << " <head><title>" << xmlescape(entry.topic()) << "</title></head>\n"
475 << " <body>\n";
476 XHTMLWriter w(ofs, 0);
477 w(entry);
478 ofs << "</body></html>\n";
479 ofs.close();
480 return true;
481 }
482