Imported Upstream version 0.3
[anytun.git] / src / logTargets.cpp
1 /*
2  *  anytun
3  *
4  *  The secure anycast tunneling protocol (satp) defines a protocol used
5  *  for communication between any combination of unicast and anycast
6  *  tunnel endpoints.  It has less protocol overhead than IPSec in Tunnel
7  *  mode and allows tunneling of every ETHER TYPE protocol (e.g.
8  *  ethernet, ip, arp ...). satp directly includes cryptography and
9  *  message authentication based on the methodes used by SRTP.  It is
10  *  intended to deliver a generic, scaleable and secure solution for
11  *  tunneling and relaying of packets of any protocol.
12  *
13  *
14  *  Copyright (C) 2007-2008 Othmar Gsenger, Erwin Nindl, 
15  *                          Christian Pointner <satp@wirdorange.org>
16  *
17  *  This file is part of Anytun.
18  *
19  *  Anytun is free software: you can redistribute it and/or modify
20  *  it under the terms of the GNU General Public License version 3 as
21  *  published by the Free Software Foundation.
22  *
23  *  Anytun is distributed in the hope that it will be useful,
24  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
25  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26  *  GNU General Public License for more details.
27  *
28  *  You should have received a copy of the GNU General Public License
29  *  along with anytun.  If not, see <http://www.gnu.org/licenses/>.
30  */
31
32 #include <sstream>
33
34 #include "datatypes.h"
35
36 #include "logTargets.h"
37 #include "log.h"
38 #include "anytunError.h"
39
40 #include "options.h"
41
42 #ifdef LOG_WINEVENTLOG
43 #include <windows.h>
44 #include <strsafe.h>
45 #endif
46
47 LogTarget::LogTarget() : opened(false), enabled(false), max_prio(Log::PRIO_NOTICE)
48 {
49 }
50
51 LogTarget::LogTarget(int prio) : opened(false), enabled(false), max_prio(prio)
52 {
53 }
54
55 LogTargetList::~LogTargetList()
56 {
57   clear();
58 }
59
60 LogTargetList::target_type_t LogTargetList::targetTypeFromString(std::string type)
61 {
62   if(type == "syslog") return TARGET_SYSLOG;
63   if(type == "file") return TARGET_FILE;
64   if(type == "stdout") return TARGET_STDOUT;
65   if(type == "stderr") return TARGET_STDERR;
66   if(type == "eventlog") return TARGET_WINEVENTLOG;
67   return TARGET_UNKNOWN;
68 }
69
70 std::string LogTargetList::targetTypeToString(target_type_t type)
71 {
72   switch(type) {
73   case TARGET_SYSLOG: return "syslog";
74   case TARGET_FILE: return "file";
75   case TARGET_STDOUT: return "stdout";
76   case TARGET_STDERR: return "stderr";
77   case TARGET_WINEVENTLOG: return "eventlog";
78   default: return "unknown";
79   }
80 }
81
82 LogTarget* LogTargetList::add(std::string conf)
83 {
84   std::stringstream s(conf);
85   std::string type;
86   getline(s, type, ':');
87   if(!s.good())
88     throw syntax_error(conf, 0);
89
90   int prio = Log::PRIO_NOTICE;
91   s >> prio;
92   if(s.fail())
93     throw syntax_error(conf, conf.find_first_of(':')+1);
94
95   char buff[100];
96   if(s.good()) {
97     s.get(buff[0]);
98     if(buff[0] != ',')
99       throw syntax_error(conf, (s.tellg() > 0) ? static_cast<size_t>(s.tellg()) - 1 : 0);
100     s.get(buff, 100);
101   }
102   else
103     buff[0] = 0;
104
105   return add(targetTypeFromString(type), prio, buff);
106 }
107
108 LogTarget* LogTargetList::add(target_type_t type, int prio, std::string conf)
109 {
110   switch(type) {
111   case TARGET_SYSLOG: {
112     #ifdef LOG_SYSLOG
113     if(!LogTargetSyslog::duplicateAllowed() && targets.count(TARGET_SYSLOG))
114       AnytunError::throwErr() << targetTypeToString(TARGET_SYSLOG) << " logtarget is supported only once";
115
116     return targets.insert(TargetsMap::value_type(TARGET_SYSLOG, new LogTargetSyslog(prio, conf)))->second;
117     #else
118     AnytunError::throwErr() << targetTypeToString(TARGET_SYSLOG) << " logtarget is not supported";
119     #endif
120   }
121   case TARGET_FILE: {
122     #ifdef LOG_FILE
123     if(!LogTargetFile::duplicateAllowed() && targets.count(TARGET_FILE))
124       AnytunError::throwErr() << targetTypeToString(TARGET_FILE) << " logtarget is supported only once";
125
126     return targets.insert(TargetsMap::value_type(TARGET_FILE, new LogTargetFile(prio, conf)))->second;
127     #else
128     AnytunError::throwErr() << targetTypeToString(TARGET_FILE) << " logtarget is not supported";
129     #endif
130   }
131   case TARGET_STDOUT: 
132   case TARGET_STDERR: {
133     #ifdef LOG_STDOUT
134     if(!LogTargetStdout::duplicateAllowed() && targets.count(type))
135       AnytunError::throwErr() << targetTypeToString(type) << " logtarget is supported only once";
136     
137     if(type == TARGET_STDERR)
138       return targets.insert(TargetsMap::value_type(type, new LogTargetStdout(prio, std::cerr)))->second;
139     else
140       return targets.insert(TargetsMap::value_type(type, new LogTargetStdout(prio, std::cout)))->second;
141     #else
142     AnytunError::throwErr() << targetTypeToString(type) + " logtarget is not supported";
143     #endif
144   }
145   case TARGET_WINEVENTLOG: {
146     #ifdef LOG_WINEVENTLOG
147     if(!LogTargetWinEventlog::duplicateAllowed() && targets.count(TARGET_WINEVENTLOG))
148       AnytunError::throwErr() << targetTypeToString(TARGET_WINEVENTLOG) << " logtarget is supported only once";
149
150     return targets.insert(TargetsMap::value_type(TARGET_WINEVENTLOG, new LogTargetWinEventlog(prio, conf)))->second;
151     #else
152     AnytunError::throwErr() << targetTypeToString(TARGET_WINEVENTLOG) << " logtarget is not supported";
153     #endif
154   }
155   default: 
156     AnytunError::throwErr() << "unknown log target";
157   }
158   return NULL;
159 }
160
161 void LogTargetList::clear()
162 {
163   TargetsMap::iterator it;
164   for(it = targets.begin(); it != targets.end(); ++it)
165     delete it->second;
166   targets.clear();
167 }
168   
169 void LogTargetList::log(std::string msg, int prio)
170 {
171   TargetsMap::const_iterator it;
172   for(it = targets.begin(); it != targets.end(); ++it) {
173     if(it->second->isEnabled() && it->second->getMaxPrio() >= prio)
174       it->second->log(msg, prio);
175   }
176 }
177
178
179 #ifdef LOG_SYSLOG
180 int LogTargetSyslog::facilityFromString(std::string fac)
181 {
182   if(fac == "user") return FAC_USER;
183   if(fac == "mail") return FAC_MAIL;
184   if(fac == "daemon") return FAC_DAEMON;
185   if(fac == "auth") return FAC_AUTH;
186   if(fac == "syslog") return FAC_SYSLOG;
187   if(fac == "lpr") return FAC_LPR;
188   if(fac == "news") return FAC_NEWS;
189   if(fac == "uucp") return FAC_UUCP;
190   if(fac == "cron") return FAC_CRON;
191   if(fac == "authpriv") return FAC_AUTHPRIV;
192   if(fac == "ftp") return FAC_FTP;
193   if(fac == "local0") return FAC_LOCAL0;
194   if(fac == "local1") return FAC_LOCAL1;
195   if(fac == "local2") return FAC_LOCAL2;
196   if(fac == "local3") return FAC_LOCAL3;
197   if(fac == "local4") return FAC_LOCAL4;
198   if(fac == "local5") return FAC_LOCAL5;
199   if(fac == "local6") return FAC_LOCAL6;
200   if(fac == "local7") return FAC_LOCAL7;
201   
202   AnytunError::throwErr() << "unknown syslog facility";
203   return 0;
204 }
205
206 std::string LogTargetSyslog::facilityToString(int fac)
207 {
208   switch(fac) {
209   case FAC_USER: return "user";
210   case FAC_MAIL: return "mail";
211   case FAC_DAEMON: return "daemon";
212   case FAC_AUTH: return "auth";
213   case FAC_SYSLOG: return "syslog";
214   case FAC_LPR: return "lpr";
215   case FAC_NEWS: return "news";
216   case FAC_UUCP: return "uucp";
217   case FAC_CRON: return "cron";
218   case FAC_AUTHPRIV: return "authpriv";
219   case FAC_FTP: return "ftp";
220   case FAC_LOCAL0: return "local0";
221   case FAC_LOCAL1: return "local1";
222   case FAC_LOCAL2: return "local2";
223   case FAC_LOCAL3: return "local3";
224   case FAC_LOCAL4: return "local4";
225   case FAC_LOCAL5: return "local5";
226   case FAC_LOCAL6: return "local6";
227   case FAC_LOCAL7: return "local7";
228   default: AnytunError::throwErr() << "unknown syslog facility";
229   }
230   return "";
231 }
232
233 LogTargetSyslog::LogTargetSyslog(int prio, std::string conf) : LogTarget(prio)
234 {
235   std::stringstream s(conf);
236   facility = FAC_DAEMON;
237   getline(s, logname, ',');
238   if(s.fail()) {
239     logname = "anytun";
240     return;
241   }
242   std::string fac;
243   getline(s, fac, ',');
244   if(s.fail())
245     return;
246
247   facility = LogTargetSyslog::facilityFromString(fac);
248 }
249
250 LogTargetSyslog::~LogTargetSyslog()
251 {
252   if(opened)
253     close();
254 }
255
256 void LogTargetSyslog::open()
257 {
258   openlog(logname.c_str(), LOG_PID, facility);
259   opened = true;
260 }
261
262 void LogTargetSyslog::close()
263 {
264   closelog();
265   opened = false;
266 }
267
268 void LogTargetSyslog::log(std::string msg, int prio)
269 {
270   if(!opened)
271     return;
272
273   syslog((prio + 2) | facility, "%s", msg.c_str());  
274 }
275
276 LogTargetSyslog& LogTargetSyslog::setLogName(std::string l)
277 {
278   logname = l;
279   if(opened)
280     close();
281   open();
282   return *this;
283 }
284
285 LogTargetSyslog& LogTargetSyslog::setFacility(int f)
286 {
287   facility = f;
288   if(opened)
289     close();
290   open();
291   return *this;
292 }
293 #endif
294
295
296 #ifdef LOG_FILE
297 LogTargetFile::LogTargetFile(int prio, std::string conf) : LogTarget(prio)
298 {
299   std::stringstream s(conf);
300   getline(s, logfilename, ',');
301   if(s.fail())
302     logfilename = "anytun.log";
303 }
304
305 LogTargetFile::~LogTargetFile()
306 {
307   if(opened)
308     close();
309 }
310
311 void LogTargetFile::open()
312 {
313   logfile.open(logfilename.c_str(), std::fstream::out | std::fstream::app);
314   opened = logfile.is_open();
315 }
316
317 void LogTargetFile::close()
318 {
319   if(logfile.is_open())
320     logfile.close();
321   opened = false;
322 }
323
324 void LogTargetFile::log(std::string msg, int prio)
325 {
326   if(!opened)
327     return;
328
329   logfile << Log::prioToString(prio) << ": " << msg << std::endl;
330 }
331
332 LogTargetFile& LogTargetFile::setLogFilename(std::string l)
333 {
334   logfilename = l;
335   if(opened)
336     close();
337   open();
338   return *this;
339 }
340 #endif
341
342
343 #ifdef LOG_STDOUT
344 LogTargetStdout::LogTargetStdout(int prio, std::ostream& s) : LogTarget(prio), stream(s)
345 {
346 }
347
348 LogTargetStdout::~LogTargetStdout()
349 {
350   if(opened)
351     close();
352 }
353
354 void LogTargetStdout::open()
355 {
356   opened = true;
357 }
358
359 void LogTargetStdout::close()
360 {
361   opened = false;
362 }
363
364 void LogTargetStdout::log(std::string msg, int prio)
365 {
366   if(!opened)
367     return;
368
369   stream << "LOG-" << Log::prioToString(prio) << ": " << msg << std::endl;
370 }
371 #endif
372
373
374 #ifdef LOG_WINEVENTLOG
375 LogTargetWinEventlog::LogTargetWinEventlog(int prio, std::string conf) : LogTarget(prio)
376 {
377   std::stringstream s(conf);
378   getline(s, logname, ',');
379   if(s.fail())
380     logname = "anytun";
381 }
382
383 LogTargetWinEventlog::~LogTargetWinEventlog()
384 {
385   if(opened)
386     close();
387 }
388
389 void LogTargetWinEventlog::open()
390 {
391   h_event_source = RegisterEventSourceA(NULL, logname.c_str());
392   if(h_event_source)
393     opened = true;
394 }
395
396 void LogTargetWinEventlog::close()
397 {
398   if(h_event_source)
399     DeregisterEventSource(h_event_source);
400   opened = false;
401 }
402
403 void LogTargetWinEventlog::log(std::string msg, int prio)
404 {
405   if(!opened)
406     return;
407
408   LPCTSTR lpszStrings[1];  
409   CHAR buffer[STERROR_TEXT_MAX];
410   StringCchPrintfA(buffer, STERROR_TEXT_MAX, "%s", msg.c_str());
411   lpszStrings[0] = buffer;
412   if(h_event_source)
413     ReportEventA(h_event_source, prioToEventLogType(prio), 0, prio, NULL, 1, 0, lpszStrings, NULL);
414 }
415
416 LogTargetWinEventlog& LogTargetWinEventlog::setLogName(std::string l)
417 {
418   logname = l;
419   if(opened)
420     close();
421   open();
422   return *this;
423 }
424
425 WORD LogTargetWinEventlog::prioToEventLogType(int prio)
426 {
427   switch(prio) {
428   case Log::PRIO_ERROR: return EVENTLOG_ERROR_TYPE;
429   case Log::PRIO_WARNING: return EVENTLOG_WARNING_TYPE;
430   case Log::PRIO_NOTICE: return EVENTLOG_INFORMATION_TYPE;
431   case Log::PRIO_INFO: return EVENTLOG_SUCCESS;
432   case Log::PRIO_DEBUG: return EVENTLOG_INFORMATION_TYPE;
433   default: return EVENTLOG_ERROR_TYPE;
434   }
435 }
436 #endif