1 /*
2 
3                           Firewall Builder
4 
5                  Copyright (C) 2009 NetCitadel, LLC
6 
7   Author:  Vadim Kurland     vadim@fwbuilder.org
8 
9   $Id$
10 
11   This program is free software which we release under the GNU General Public
12   License. You may redistribute and/or modify this program under the terms
13   of that license as published by the Free Software Foundation; either
14   version 2 of the License, or (at your option) any later version.
15 
16   This program is distributed in the hope that it will be useful,
17   but WITHOUT ANY WARRANTY; without even the implied warranty of
18   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   GNU General Public License for more details.
20 
21   To get a copy of the GNU General Public License, write to the Free Software
22   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 
24 */
25 
26 #include "config.h"
27 #include "fwbuilder/libfwbuilder-config.h"
28 
29 #include <assert.h>
30 
31 #include "BaseCompiler.h"
32 
33 #include <iostream>
34 #include <iomanip>
35 #include <algorithm>
36 #include <functional>
37 #include <fstream>
38 #include <string>
39 
40 
41 using namespace libfwbuilder;
42 using namespace fwcompiler;
43 using namespace std;
44 
45 
FWCompilerException(Rule * r,const string & err)46 FWCompilerException::FWCompilerException(Rule *r, const string &err) : FWException(err)
47 {
48     rule=r;
49 }
50 
51 
haveErrorsAndWarnings()52 bool BaseCompiler::haveErrorsAndWarnings()
53 {
54     return (int(errors_buffer.tellp()) > 0);
55 }
56 
getErrors(const string & comment_sep)57 string BaseCompiler::getErrors(const string &comment_sep)
58 {
59     ostringstream ostr;
60     istringstream istr(errors_buffer.str());
61     while (!istr.eof())
62     {
63         string tmpstr;
64         getline(istr, tmpstr);
65         if (tmpstr.length())
66             ostr << comment_sep << tmpstr << endl;
67     }
68     return ostr.str();
69 }
70 
clearErrors()71 void BaseCompiler::clearErrors()
72 {
73     errors_buffer.str("");
74     rule_errors.clear();
75 }
76 
getErrorsForRule(Rule * rule,const std::string & comment_sep)77 string BaseCompiler::getErrorsForRule(Rule *rule, const std::string &comment_sep)
78 {
79     string rule_label = rule->getLabel();
80     rule_errors[rule_label].sort();
81     ostringstream ostr;
82     list<string>::iterator it;
83     string prev;  // used to remove duplicate messages
84     for (it=rule_errors[rule_label].begin(); it!=rule_errors[rule_label].end(); ++it)
85     {
86         if (*it != prev) ostr << comment_sep << *it << endl;
87         prev = *it;
88     }
89     return ostr.str();
90 }
91 
92 
93 /*
94  * Error and warning format:
95  *
96  *  fw-object-name:ruleset-name:rule-number: message
97  */
stdErrorMessage(FWObject * fw,FWObject * ruleset,FWObject * rule,const std::string & errstr)98 string BaseCompiler::stdErrorMessage(FWObject *fw,
99                                      FWObject *ruleset,
100                                      FWObject *rule,
101                                      const std::string &errstr)
102 {
103     ostringstream tmpstr;
104 
105     // TODO: (some day) get rid of the argument @fw and use attribute
106     // ".ruleset_owner" instead. Set this attribute in the place where
107     // we prepare rules for processing and copy them to the
108     // queue. This way, when CompilerDriver prepares rules from the
109     // cluster, it can override the same attribute to make error and
110     // warning messges refer to correct object that really owns rule
111     // sets.
112     string ruleset_owner;
113     if (ruleset)
114     {
115         ruleset_owner = ruleset->getStr(".ruleset_owner");
116     }
117     if (ruleset_owner.empty() && fw) ruleset_owner = fw->getName();
118 
119     tmpstr << ruleset_owner << ":";
120     if (ruleset) tmpstr << ruleset->getName();
121     tmpstr << ":";
122     if (rule && Rule::cast(rule)) tmpstr << Rule::cast(rule)->getPosition();
123     tmpstr << ": ";
124     tmpstr << level_macro << ": ";
125     tmpstr << errstr;
126     return tmpstr.str();
127 }
128 
setLevel(const string & level,const string & errstr)129 string BaseCompiler::setLevel(const string &level, const string &errstr)
130 {
131     string str = errstr;
132     while (str.at(str.length() - 1) == '\n') str = str.substr(0, str.length() - 1);
133     size_t n = str.find(level_macro);
134     if (n != string::npos) str.replace(n, level_macro.length(), level);
135     return str;
136 }
137 
message(const std::string & level,FWObject * fw,FWObject * ruleset,FWObject * rule,const string & errstr)138 void BaseCompiler::message(const std::string &level,
139                            FWObject *fw,
140                            FWObject *ruleset,
141                            FWObject *rule,
142                            const string &errstr)
143 {
144     string str = setLevel(level, stdErrorMessage(fw, ruleset, rule, errstr));
145     printError(str);
146     Rule *cast_rule = Rule::cast(rule);
147     if (cast_rule)
148     {
149         cast_rule->setCompilerMessage(str);
150         rule_errors[cast_rule->getLabel()].push_back(str);
151     }
152 }
153 
printError(const string & errstr)154 void BaseCompiler::printError(const string &errstr)
155 {
156     if (!inEmbeddedMode())
157     {
158         cout << flush;
159         cerr << errstr << endl;
160     }
161     errors_buffer << errstr << endl;
162 }
163 
164 /*
165  * Note that when this code runs as part of the command line compiler
166  * rather than as a single-rule compile function inside the GUI (that
167  * is, it is not in embedded mode) and if test mode was activated
168  * (usually via command line flag "-xt"), then abort() behaves as
169  * error(), that is, it prints error message but does not terminate
170  * the process but just returns. In embedded mode it always throws
171  * exception to stop compiling
172  */
abort(const string & errstr)173 void BaseCompiler::abort(const string &errstr) throw(FWException)
174 {
175     printError(errstr);
176     if (inEmbeddedMode())
177         throw FatalErrorInSingleRuleCompileMode(errors_buffer.str());
178     status = FWCOMPILER_ERROR;
179     if (test_mode) return;
180     throw FWException("Fatal error");
181 }
182 
abort(FWObject * fw,FWObject * ruleset,FWObject * rule,const string & errstr)183 void BaseCompiler::abort(FWObject *fw,
184                          FWObject *ruleset,
185                          FWObject *rule,
186                          const string &errstr) throw(FWException)
187 {
188     message("error", fw, ruleset, rule, errstr);
189     if (inEmbeddedMode())
190         throw FatalErrorInSingleRuleCompileMode(errors_buffer.str());
191     status = FWCOMPILER_ERROR;
192     if (test_mode) return;
193     throw FWException("Fatal error");
194 }
195 
error(const string & str)196 void BaseCompiler::error(const string &str)
197 {
198     status = FWCOMPILER_ERROR;
199     printError(str);
200 }
201 
error(FWObject * fw,FWObject * ruleset,FWObject * rule,const string & errstr)202 void BaseCompiler::error(FWObject *fw,
203                          FWObject *ruleset,
204                          FWObject *rule,
205                          const string &errstr)
206 {
207     status = FWCOMPILER_ERROR;
208     message("error", fw, ruleset, rule, errstr);
209 }
210 
warning(const string & str)211 void BaseCompiler::warning(const string &str)
212 {
213     status = FWCOMPILER_WARNING;
214     printError(str);
215 }
216 
warning(FWObject * fw,FWObject * ruleset,FWObject * rule,const string & errstr)217 void BaseCompiler::warning(FWObject *fw,
218                            FWObject *ruleset,
219                            FWObject *rule,
220                            const string &errstr)
221 {
222     status = FWCOMPILER_WARNING;
223     message("warning", fw, ruleset, rule, errstr);
224 }
225 
info(const string & str)226 void BaseCompiler::info(const string &str)
227 {
228     if (!inEmbeddedMode())
229     {
230         cout << str << endl << flush;
231     }
232 }
233 
errorRegExp(std::list<std::string> * err_regexp)234 void BaseCompiler::errorRegExp(std::list<std::string> *err_regexp)
235 {
236     err_regexp->clear();
237     err_regexp->push_back("([^:]*):([^:]*):.*[Ee]rror:");
238     err_regexp->push_back("(Error(:| )[^\n]*)");
239 }
240 
warningRegExp(std::list<std::string> * warn_regexp)241 void BaseCompiler::warningRegExp(std::list<std::string> *warn_regexp)
242 {
243     warn_regexp->clear();
244     warn_regexp->push_back("([^:]*):([^:]*):.*[Ww]arning:");
245     warn_regexp->push_back("(Warning(:| )[^\n]*)");
246 }
247 
248