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 <cctype>
31 #include <cerrno>
32 #include <cstdlib>
33 #include <fstream>
34 #include <iostream>
35 #include <map>
36 #include <memory>
37 #include <sstream>
38 #include <stack>
39 #include <string>
40 #include <vector>
41 
42 #include <unistd.h>
43 
44 #include <vuxml/vuxml.hh>
45 #include <vuxml/constants.hh>
46 #include <vuxml/parser.hh>
47 #include <vuxml/handlers.hh>
48 
49 
50 using namespace vuxml;
51 
52 
BasicHandler(EntryProcessor & proc)53 BasicHandler::BasicHandler(EntryProcessor &proc)
54     : parser_(0), proc_(proc), state_(&F_docroot)
55 #define CLASS BasicHandler
56 #include <vuxml/state_init.hh>
57 #include <vuxml/state_head.hh>
58 #include <vuxml/basic_state.hh>
59 #include <vuxml/state_undef.hh>
60 {
61 #if defined(DEBUG_STATE)
62 #include <vuxml/state_debug.hh>
63 #include <vuxml/state_head.hh>
64 #include <vuxml/basic_state.hh>
65 #include <vuxml/state_undef.hh>
66 #endif
67 }
68 
69 
~BasicHandler()70 BasicHandler::~BasicHandler()
71 {
72 }
73 
74 
75 XMLState *
signalError_(const char * msg)76 BasicHandler::signalError_(const char *msg)
77 {
78 	parser_->signalError(msg);
79 	return &F_ignore;
80 }
81 
82 
83 XMLState *
docroot_child(const Element & element)84 BasicHandler::docroot_child(const Element &element)
85 {
86 	if (element.id() != T_vuxml)
87 		return signalError_("Not a VuXML document.");
88 	return &F_vuxml;
89 }
90 
91 
92 XMLState *
vuxml_child(const Element & element)93 BasicHandler::vuxml_child(const Element &element)
94 {
95 	if (element.id() != T_vuln)
96 		return signalError_("Expected `vuln' element.");
97 	return &F_vuln0;
98 }
99 
100 
101 XMLState *
vuxml_end(const Element & element)102 BasicHandler::vuxml_end(const Element &element)
103 {
104 	if (element.id() != T_vuxml)
105 		return &F_dead;
106 	return state_;
107 }
108 
109 
110 XMLState *
vuln0_child(const Element & element)111 BasicHandler::vuln0_child(const Element &element)
112 {
113 	if (element.id() == T_topic)
114 		return &F_topic;
115 	else if (element.id() == T_cancelled)
116 		return &F_cxl;
117 	else
118 		return signalError_("Expected `topic' element.");
119 }
120 
121 
122 namespace {
isValidVidCharacter(char c)123 bool isValidVidCharacter(char c) {
124 	using std::islower;
125 	using std::isdigit;
126 	return (islower(c) || isdigit(c) || c == '-');
127 }
128 }
129 
130 
131 void
vuln0_start(const Element & __unused element,Attributes & attr)132 BasicHandler::vuln0_start(const Element & __unused element,
133     Attributes &attr)
134 {
135 	entry_.reset(new Entry);
136 	std::string vid = killspace(attr["vid"]);
137 	if (vid.size() == 0) {
138 		signalError_("Empty or missing `vid' attribute.");
139 		return;
140 	}
141 	std::transform(vid.begin(), vid.end(), vid.begin(), ::tolower);
142 	std::string::const_iterator p = std::find_if(vid.begin(), vid.end(),
143 	    std::not1(std::ptr_fun(isValidVidCharacter)));
144 	if (p != vid.end()) {
145 		signalError_("Malformed `vid' attribute.");
146 		return;
147 	}
148 	entry_->setVid(vid);
149 }
150 
151 
152 void
tmp_start(const Element & __unused element,Attributes & __unused attr)153 BasicHandler::tmp_start(const Element & __unused element,
154     Attributes & __unused attr)
155 {
156 	tmp_ = std::string();
157 }
158 
159 
160 void
tmp_characters(std::string & pcdata)161 BasicHandler::tmp_characters(std::string &pcdata)
162 {
163 	tmp_ += pcdata;
164 }
165 
166 
167 XMLState *
topic_end(const Element & __unused element)168 BasicHandler::topic_end(const Element & __unused element)
169 {
170 	entry_->setTopic(killspace(tmp_));
171 	return &F_vuln1;
172 }
173 
174 
175 XMLState *
vuln1_child(const Element & element)176 BasicHandler::vuln1_child(const Element &element)
177 {
178 	if (element.id() != T_affects)
179 		return signalError_("Expected `affects' element.");
180 	return &F_affects;
181 }
182 
183 
184 XMLState *
affects_child(const Element & element)185 BasicHandler::affects_child(const Element &element)
186 {
187 	switch (element.id()) {
188 	case T_package:
189 		return &F_package;
190 	case T_system:
191 		return &F_system;
192 	default:
193 		return signalError_("Expected `package' or `system' element.");
194 	}
195 }
196 
197 
198 XMLState *
affects_end(const Element & element)199 BasicHandler::affects_end(const Element &element)
200 {
201 	if (element.id() != T_affects)
202 		return &F_dead;
203 	return &F_vuln2;
204 }
205 
206 
207 XMLState *
package_child(const Element & element)208 BasicHandler::package_child(const Element &element)
209 {
210 	switch (element.id()) {
211 	case T_name:
212 		push_state(state_);
213 		return &F_name;
214 	case T_range:
215 		push_state(state_);
216 		return &F_range;
217 	default:
218 		return signalError_("Expected `name' or `range' element.");
219 	}
220 }
221 
222 
223 void
package_start(const Element & __unused element,Attributes & __unused attr)224 BasicHandler::package_start(const Element & __unused element,
225     Attributes & __unused attr)
226 {
227 	entry_->addAffectedSet();
228 }
229 
230 
231 XMLState *
package_end(const Element & element)232 BasicHandler::package_end(const Element &element)
233 {
234 	if (element.id() != T_package && element.id() != T_system)
235 		return &F_dead;
236 	return &F_affects;
237 }
238 
239 
240 XMLState *
name_end(const Element & __unused element)241 BasicHandler::name_end(const Element & __unused element)
242 {
243 	entry_->addAffectedName(killspace(tmp_));
244 	return pop_state();
245 }
246 
247 
248 XMLState *
range_child(const Element & element)249 BasicHandler::range_child(const Element &element)
250 {
251 	switch (element.id()) {
252 	case T_gt:
253 	case T_ge:
254 	case T_lt:
255 	case T_le:
256 	case T_eq:
257 		return &F_rangeop;
258 	default:
259 		return signalError_("Expected range operator element.");
260 	}
261 }
262 
263 
264 void
range_start(const Element & __unused element,Attributes & __unused attr)265 BasicHandler::range_start(const Element & __unused element,
266     Attributes & __unused attr)
267 {
268 	range_ = VersionRange();
269 }
270 
271 
272 XMLState *
range_end(const Element & __unused element)273 BasicHandler::range_end(const Element & __unused element)
274 {
275 	entry_->addAffectedRange(range_);
276 	return pop_state();
277 }
278 
279 
280 XMLState *
rangeop_end(const Element & element)281 BasicHandler::rangeop_end(const Element &element)
282 {
283 	tmp_ = killspace(tmp_);
284 	switch (element.id()) {
285 	case T_gt:
286 		range_.lo_closed = false;
287 		// fallthrough
288 	case T_ge:
289 		range_.lo = tmp_;
290 		break;
291 	case T_lt:
292 		range_.hi_closed = false;
293 		// fallthrough
294 	case T_le:
295 		range_.hi = tmp_;
296 		break;
297 	case T_eq:
298 		range_.hi = range_.lo = tmp_;
299 		break;
300 	default:
301 		throw except("Internal error: rangeop_end, bad element");
302 	}
303 	return &F_range;
304 }
305 
306 
307 
308 namespace {
309 class appendAttribute : public std::unary_function<void,
310     std::pair<const std::string, std::string> &> {
311 private:
312   std::string &s_;
313 public:
appendAttribute(std::string & s)314   appendAttribute(std::string &s) : s_(s) {}
operator ()(std::pair<const std::string,std::string> & item)315   void operator()(std::pair<const std::string, std::string> &item) {
316 	  s_ += ' ';
317 	  s_ += item.first;
318 	  s_ += "=\"";
319 	  s_ += xmlescape(item.second);
320 	  s_ += '"';
321   }
322 };
323 }
324 
325 
326 XMLState *
vuln2_child(const Element & element)327 BasicHandler::vuln2_child(const Element &element)
328 {
329 	if (element.id() != T_description)
330 		return signalError_("Expected `description' element.");
331 	return &F_description;
332 }
333 
334 
335 void
description_start(const Element & element,Attributes & attr)336 BasicHandler::description_start(const Element &element, Attributes &attr)
337 {
338 	std::string s;
339 	switch (element.id()) {
340 	case T_description:
341 		break;
342 	case T_XHTML_BODY:
343 		break;
344 	case T_XHTML:
345 		s += '<';
346 		s += element.name();
347 		if (element.id() == T_XHTML_BODY) {
348 			s += " xmlns=\"";
349 			s += XHTML_NAMESPACE;
350 			s += '"';
351 		}
352 		std::for_each(attr.begin(), attr.end(), appendAttribute(s));
353 		s += '>';
354 		entry_->appendDescription(s);
355 		break;
356 	default:
357 		signalError_("Expected element in XHTML namespace.");
358 		break;
359 	}
360 }
361 
362 
363 void
description_characters(std::string & pcdata)364 BasicHandler::description_characters(std::string &pcdata)
365 {
366 	entry_->appendDescription(xmlescape(pcdata));
367 }
368 
369 
370 XMLState *
description_end(const Element & element)371 BasicHandler::description_end(const Element &element)
372 {
373 	if (element.id() == T_description)
374 		return &F_vuln3;
375 	else if (element.id() == T_XHTML_BODY)
376 		return state_;
377 	std::string s;
378 	s += "</";
379 	s += element.name();
380 	s += '>';
381 	entry_->appendDescription(s);
382 	return state_;
383 }
384 
385 
386 XMLState *
vuln3_child(const Element & element)387 BasicHandler::vuln3_child(const Element &element)
388 {
389 	if (element.id() != T_references)
390 		return signalError_("Expected `references' element.");
391 	return &F_references;
392 }
393 
394 
395 XMLState *
references_child(const Element & element)396 BasicHandler::references_child(const Element &element)
397 {
398 	switch (element.id()) {
399 	case T_url:
400 	case T_cvename:
401 	case T_freebsdsa:
402 	case T_bid:
403 	case T_certsa:
404 	case T_certvu:
405 	case T_mlist:
406 	case T_uscertsa:
407 	case T_uscertta:
408 	case T_freebsdpr:
409 		return &F_reference;
410 	default:
411 		return signalError_("Expected a reference element.");
412 	}
413 }
414 
415 
416 XMLState *
references_end(const Element & element)417 BasicHandler::references_end(const Element &element)
418 {
419 	if (element.id() != T_references)
420 		return &F_dead;
421 	return &F_vuln4;
422 }
423 
424 
425 XMLState *
reference_end(const Element & element)426 BasicHandler::reference_end(const Element &element)
427 {
428 	entry_->addReference(element.name(), killspace(tmp_));
429 	return &F_references;
430 }
431 
432 
433 XMLState *
vuln4_child(const Element & element)434 BasicHandler::vuln4_child(const Element &element)
435 {
436 	if (element.id() != T_dates)
437 		return signalError_("Expected `dates' element.");
438 	return &F_dates0;
439 }
440 
441 
442 XMLState *
dates0_child(const Element & element)443 BasicHandler::dates0_child(const Element &element)
444 {
445 	if (element.id() != T_discovery)
446 		return signalError_("Expected `discovery' element.");
447 	return &F_discovery;
448 }
449 
450 
451 XMLState *
discovery_end(const Element & __unused element)452 BasicHandler::discovery_end(const Element & __unused element)
453 {
454 	entry_->setDiscoveryDate(killspace(tmp_));
455 	return &F_dates1;
456 }
457 
458 
459 XMLState *
dates1_child(const Element & element)460 BasicHandler::dates1_child(const Element &element)
461 {
462 	if (element.id() != T_entry)
463 		return signalError_("Expected `entry' element.");
464 	return &F_entry;
465 }
466 
467 
468 XMLState *
entry_end(const Element & __unused element)469 BasicHandler::entry_end(const Element & __unused element)
470 {
471 	entry_->setEntryDate(killspace(tmp_));
472 	return &F_dates2;
473 }
474 
475 
476 XMLState *
dates2_child(const Element & element)477 BasicHandler::dates2_child(const Element &element)
478 {
479 	if (element.id() != T_modified)
480 		return signalError_("Expected `modified' element.");
481 	return &F_modified;
482 }
483 
484 
485 XMLState *
modified_end(const Element & __unused element)486 BasicHandler::modified_end(const Element & __unused element)
487 {
488 	entry_->setModifiedDate(killspace(tmp_));
489 	return &F_dates3;
490 }
491 
492 
493 XMLState *
dates2_end(const Element & element)494 BasicHandler::dates2_end(const Element &element)
495 {
496 	if (element.id() != T_dates)
497 		return &F_dead;
498 	return &F_vuln5;
499 }
500 
501 
502 XMLState *
vuln5_end(const Element & element)503 BasicHandler::vuln5_end(const Element &element)
504 {
505 	if (element.id() == T_vuln) {
506 		proc_(*entry_);
507 		return &F_vuxml;
508 	}
509 	return state_;
510 }
511 
512 
513 XMLState *
cxl_end(const Element & element)514 BasicHandler::cxl_end(const Element &element)
515 {
516 	return &F_vuln5;
517 }
518 
519 
520 void
setParser(Parser & parser)521 BasicHandler::setParser(Parser &parser)
522 {
523 	parser_ = &parser;
524 }
525 
526 
527 XMLState *
top_state()528 BasicHandler::top_state()
529 {
530 	return state_stack_.top();
531 }
532 
533 
534 XMLState *
pop_state()535 BasicHandler::pop_state()
536 {
537 	XMLState *s = state_stack_.top();
538 	state_stack_.pop();
539 	return s;
540 }
541 
542 
543 void
push_state(XMLState * state)544 BasicHandler::push_state(XMLState *state)
545 {
546 	state_stack_.push(state);
547 }
548 
549 
550 void
startElement(std::string & xmlns,std::string & name,Attributes & attr)551 BasicHandler::startElement(std::string &xmlns, std::string &name,
552     Attributes &attr)
553 {
554 	Element element(xmlns, name);
555 #if defined(DEBUG_STATE)
556 	LOG << "child state=" << static_cast<void *>(state_) << '\n';
557 #endif
558 	state_ = state_->child(element);
559 #if defined(DEBUG_STATE)
560 	LOG << "start state=" << static_cast<void *>(state_) << '\n';
561 #endif
562 	state_->start(element, attr);
563 }
564 
565 
566 void
characters(std::string & pcdata)567 BasicHandler::characters(std::string &pcdata)
568 {
569 #if defined(DEBUG_STATE)
570 	LOG << "characters state=" << static_cast<void *>(state_) << '\n';
571 #endif
572 	state_->characters(pcdata);
573 }
574 
575 
576 void
endElement(std::string & xmlns,std::string & name)577 BasicHandler::endElement(std::string &xmlns, std::string &name)
578 {
579 	Element element(xmlns, name);
580 #if defined(DEBUG_STATE)
581 	LOG << "end state=" << static_cast<void *>(state_) << '\n';
582 #endif
583 	state_ = state_->end(element);
584 }
585 
586 
587 XMLState *
dead_child(const Element & __unused element)588 BasicHandler::dead_child(const Element & __unused element)
589 {
590 	return signalError_("Start of element unexpected.");
591 }
592 
593 
594 void
dead_start(const Element & __unused element,Attributes & __unused attr)595 BasicHandler::dead_start(const Element & __unused element,
596     Attributes & __unused attr)
597 {
598 	signalError_("Attributes unexpected.");
599 }
600 
601 
602 void
dead_characters(std::string & __unused pcdata)603 BasicHandler::dead_characters(std::string & __unused pcdata)
604 {
605 	signalError_("Character data unexpected.");
606 }
607 
608 
609 XMLState *
dead_end(const Element & __unused element)610 BasicHandler::dead_end(const Element & __unused element)
611 {
612 	return signalError_("End of element unexpected.");
613 }
614 
615 
616 XMLState *
ignore_child(const Element & __unused element)617 BasicHandler::ignore_child(const Element & __unused element)
618 {
619 	return state_;
620 }
621 
622 
623 void
ignore_start(const Element & __unused element,Attributes & __unused attr)624 BasicHandler::ignore_start(const Element & __unused element,
625     Attributes & __unused attr)
626 {
627 }
628 
629 
630 void
ignore_characters(std::string & __unused pcdata)631 BasicHandler::ignore_characters(std::string & __unused pcdata)
632 {
633 }
634 
635 
636 XMLState *
ignore_end(const Element & __unused element)637 BasicHandler::ignore_end(const Element & __unused element)
638 {
639 	return state_;
640 }
641