1 /* SAMHAIN file system integrity testing                                   */
2 /* Copyright (C) 1999, 2000 Rainer Wichmann                                */
3 /*                                                                         */
4 /*  This program is free software; you can redistribute it                 */
5 /*  and/or modify                                                          */
6 /*  it under the terms of the GNU General Public License as                */
7 /*  published by                                                           */
8 /*  the Free Software Foundation; either version 2 of the License, or      */
9 /*  (at your option) any later version.                                    */
10 /*                                                                         */
11 /*  This program is distributed in the hope that it will be useful,        */
12 /*  but WITHOUT ANY WARRANTY; without even the implied warranty of         */
13 /*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
14 /*  GNU General Public License for more details.                           */
15 /*                                                                         */
16 /*  You should have received a copy of the GNU General Public License      */
17 /*  along with this program; if not, write to the Free Software            */
18 /*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
19 
20 #include "config_xor.h"
21 
22 #include <string.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <syslog.h>
26 
27 /* Must be early on FreeBSD
28  */
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <netdb.h>
32 #include <netinet/in.h>
33 
34 #if TIME_WITH_SYS_TIME
35 #include <sys/time.h>
36 #include <time.h>
37 #else
38 #if HAVE_SYS_TIME_H
39 #include <sys/time.h>
40 #else
41 #include <time.h>
42 #endif
43 #endif
44 
45 #include <unistd.h>
46 #include <fcntl.h>
47 
48 #ifdef SH_WITH_SERVER
49 
50 #include "samhain.h"
51 #include "sh_tools.h"
52 #include "sh_utils.h"
53 #include "sh_ipvx.h"
54 
55 #undef  FIL__
56 #define FIL__  _("sh_xfer_syslog.c")
57 
58 #ifdef INET_SYSLOG
59 
60 extern void sh_xfer_printerr(char * str, int errnum, unsigned int port, int line);
61 extern int sh_xfer_syslog_sock[SH_SOCKMAX];
62 extern int sh_xfer_syslog_sock_n;
63 extern int SH_MINSOCK;
64 
65 /* Unlike Linux / FreeBSD, most systems don't define the stuff below
66  * in syslog.h
67  */
68 
69 #ifndef LOG_FAC
70 #define LOG_FAC(p)      (((p) & LOG_FACMASK) >> 3)
71 #endif
72 
73 #ifndef LOG_PRI
74 #define LOG_PRI(p)      ((p) & LOG_PRIMASK)
75 #endif
76 
77 typedef struct sh_code {
78         char    *c_name;
79         int     c_val;
80 } SH_CODE;
81 
82 SH_CODE sh_facilitynames[] =
83 {
84 #ifdef LOG_AUTH
85   { N_("auth"), LOG_AUTH },
86 #endif
87 #ifdef LOG_AUTHPRIV
88   { N_("authpriv"), LOG_AUTHPRIV },
89 #endif
90 #ifdef LOG_CRON
91   { N_("cron"), LOG_CRON },
92 #endif
93 #ifdef LOG_DAEMON
94   { N_("daemon"), LOG_DAEMON },
95 #endif
96 #ifdef LOG_FTP
97   { N_("ftp"), LOG_FTP },
98 #endif
99 #ifdef LOG_KERN
100   { N_("kern"), LOG_KERN },
101 #endif
102 #ifdef LOG_LPR
103   { N_("lpr"), LOG_LPR },
104 #endif
105 #ifdef LOG_MAIL
106   { N_("mail"), LOG_MAIL },
107 #endif
108 #ifdef INTERNAL_MARK
109   { N_("mark"), INTERNAL_MARK },          /* INTERNAL */
110 #endif
111 #ifdef LOG_NEWS
112   { N_("news"), LOG_NEWS },
113 #endif
114 #ifdef LOG_AUTH
115   { N_("security"), LOG_AUTH },           /* DEPRECATED */
116 #endif
117 #ifdef LOG_SYSLOG
118   { N_("syslog"), LOG_SYSLOG },
119 #endif
120 #ifdef LOG_USER
121   { N_("user"), LOG_USER },
122 #endif
123 #ifdef LOG_UUCP
124   { N_("uucp"), LOG_UUCP },
125 #endif
126 #ifdef LOG_LOCAL0
127   { N_("local0"), LOG_LOCAL0 },
128 #endif
129 #ifdef LOG_LOCAL1
130   { N_("local1"), LOG_LOCAL1 },
131 #endif
132 #ifdef LOG_LOCAL2
133   { N_("local2"), LOG_LOCAL2 },
134 #endif
135 #ifdef LOG_LOCAL3
136   { N_("local3"), LOG_LOCAL3 },
137 #endif
138 #ifdef LOG_LOCAL4
139   { N_("local4"), LOG_LOCAL4 },
140 #endif
141 #ifdef LOG_LOCAL5
142   { N_("local5"), LOG_LOCAL5 },
143 #endif
144 #ifdef LOG_LOCAL6
145   { N_("local6"), LOG_LOCAL6 },
146 #endif
147 #ifdef LOG_LOCAL7
148   { N_("local7"), LOG_LOCAL7 },
149 #endif
150   { NULL, -1 }
151 };
152 
153 
154 SH_CODE sh_prioritynames[] =
155 {
156 #ifdef LOG_ALERT
157   { N_("alert"), LOG_ALERT },
158 #endif
159 #ifdef LOG_CRIT
160   { N_("crit"), LOG_CRIT },
161 #endif
162 #ifdef LOG_DEBUG
163   { N_("debug"), LOG_DEBUG },
164 #endif
165 #ifdef LOG_EMERG
166   { N_("emerg"), LOG_EMERG },
167 #endif
168 #ifdef LOG_ERR
169   { N_("err"), LOG_ERR },
170 #endif
171 #ifdef LOG_ERR
172   { N_("error"), LOG_ERR },               /* DEPRECATED */
173 #endif
174 #ifdef LOG_INFO
175   { N_("info"), LOG_INFO },
176 #endif
177 #ifdef INTERNAL_NOPRI
178   { N_("none"), INTERNAL_NOPRI },         /* INTERNAL */
179 #endif
180 #ifdef LOG_NOTICE
181   { N_("notice"), LOG_NOTICE },
182 #endif
183 #ifdef LOG_EMERG
184   { N_("panic"), LOG_EMERG },             /* DEPRECATED */
185 #endif
186 #ifdef LOG_WARNING
187   { N_("warn"), LOG_WARNING },            /* DEPRECATED */
188 #endif
189 #ifdef LOG_WARNING
190   { N_("warning"), LOG_WARNING },
191 #endif
192   { NULL, -1 }
193 };
194 
195 static int enable_syslog_socket = S_FALSE;
196 
sh_xfer_recv_syslog_socket(int fd)197 int sh_xfer_recv_syslog_socket (int fd)
198 {
199   static time_t      return_next = 0;
200   int                priority = 0;
201   int                fac, pri;
202   int                i;
203   char             * cfac = NULL;
204   char             * cpri = NULL;
205   int                res;
206   char             * tmp;
207   char             * bptr;
208   char             * ptr = NULL;
209   char               buf[1048];
210   struct sockaddr_in from;
211   char errbuf[SH_ERRBUF_SIZE];
212 
213   struct sh_sockaddr ss;
214   struct sockaddr * sa = (struct sockaddr *) &from;
215   char   namebuf[SH_BUFSIZE];
216 
217   /* The 6th argument in recvfrom is *socklen_t in Linux and *BSD,
218    * but *int everywhere else. Because socklen_t is unsigned int, there
219    * should be no problem as long as  sizeof(struct sockaddr_in) < INT_MAX ...
220    */
221   unsigned int fromlen = sizeof(from);
222 
223   if (enable_syslog_socket == S_FALSE)
224     return 0;
225 
226   SL_ENTER(_("sh_xfer_recv_syslog_socket"));
227 
228   if (return_next > 0)
229     {
230       if ( (time(NULL) - return_next) < 2)
231 	SL_RETURN( 0, _("sh_xfer_recv_syslog_socket"));
232       else
233 	return_next = 0;
234     }
235 
236   res = recvfrom(fd,  buf,  1047, 0, (struct sockaddr *) &from, &fromlen);
237 
238   sh_ipvx_save(&ss, sa->sa_family, (struct sockaddr *) &from);
239   sh_ipvx_ntoa(namebuf, sizeof(namebuf), &ss);
240 
241   if (res > 0)
242     {
243       res = (res < 1047) ? res : 1047;
244       buf[res] = '\0';
245       if (res > 1 && buf[res-1] == '\n')
246 	buf[res-1] = '\0';
247 
248       /* here we expect an xml formatted message, thus we don't
249 	 escape xml special chars (flag == 0) */
250       /* commented out to not escape twice    */
251       /* bptr = sh_tools_safe_name(buf, 0);   */
252       bptr = buf;
253 
254       if (!bptr || !(*bptr))
255 	{
256 	  res = errno;
257 	  TPT(( 0, FIL__, __LINE__, _("msg=<UDP error: %d>\n"), res));
258 	  sh_error_handle((-1), FIL__, __LINE__, res, MSG_ERR_SYSLOG,
259 			  sh_error_message(res, errbuf, sizeof(errbuf)),
260 			  namebuf);
261 	  SL_RETURN( (-1), _("sh_xfer_recv_syslog_socket"));
262 	}
263 
264       TPT(( 0, FIL__, __LINE__, _("msg=<UDP message from %s>\n"), namebuf ));
265 
266       ptr = bptr;
267       i = 0;
268       if (*ptr == '<')
269 	{
270 	  ++ptr; ++i;
271 	  while (i < res &&
272 		 (unsigned char) *ptr > 47 && (unsigned char) *ptr < 58)
273 	    {
274 	      priority = 10 * priority + (*ptr - '0');
275 	      ++ptr;
276 	      ++i;
277 	    }
278 	  if (*ptr == '>')
279 	    ++ptr;
280 	}
281       fac = LOG_FAC(priority);
282       i = 0;
283       while (sh_facilitynames[i].c_name != NULL)
284 	{
285 	  if (sh_facilitynames[i].c_val == (fac<<3))
286 	    { cfac = sh_util_strdup(_(sh_facilitynames[i].c_name)); break; }
287 	  ++i;
288 	}
289       pri = LOG_PRI(priority);
290       i = 0;
291       while (sh_prioritynames[i].c_name != NULL)
292 	{
293 	  if (sh_prioritynames[i].c_val == pri)
294 	    { cpri = sh_util_strdup(_(sh_prioritynames[i].c_name)); break; }
295 	  ++i;
296 	}
297 
298       /* here we do not expect an xml formatted message, thus we escape
299 	 xml special chars (flag == 1) */
300       tmp = sh_tools_safe_name (ptr, 1);
301       sh_error_handle((-1), FIL__, __LINE__, 0, MSG_INET_SYSLOG,
302 		      namebuf,
303 		      (cfac == NULL) ? _("none") : cfac,
304 		      (cpri == NULL) ? _("none") : cpri,
305 		      (tmp  == NULL) ? _("none") : tmp);
306       if (cfac != NULL)
307 	SH_FREE(cfac);
308       if (cpri != NULL)
309 	SH_FREE(cpri);
310       SH_FREE(tmp);
311       /* SH_FREE(bptr); */
312     }
313 
314   else if (res < 0 && errno != EINTR)
315     {
316       res = errno;
317       TPT(( 0, FIL__, __LINE__, _("msg=<UDP error: %d>\n"), res));
318       sh_error_handle((-1), FIL__, __LINE__, res, MSG_ERR_SYSLOG,
319 		      sh_error_message(res, errbuf, sizeof(errbuf)),
320 		      namebuf);
321 
322       /* don't accept anything the next 2 seconds
323        */
324       return_next = time(NULL);
325       SL_RETURN( (-1), _("sh_xfer_recv_syslog_socket"));
326     }
327   SL_RETURN( (0), _("sh_xfer_recv_syslog_socket"));
328 }
329 
set_syslog_active(const char * c)330 int set_syslog_active(const char * c)
331 {
332   return sh_util_flagval(c, &enable_syslog_socket);
333 }
334 
do_syslog_socket(int domain,int type,int protocol,struct sockaddr * sa,int salen)335 static int do_syslog_socket(int domain, int type, int protocol,
336 			    struct sockaddr * sa, int salen)
337 {
338   int                flag = 1;  /* non-zero to enable an option */
339   int sock;
340   int errnum;
341   int res;
342 
343   /* create the socket, bind() it and listen()
344    */
345   sock = socket(domain, type, protocol);
346 
347   if (sock < 0)
348     {
349       errnum = errno;
350       sh_xfer_printerr (_("syslog socket"), errnum, 514, __LINE__);
351       return -1;
352     }
353   (void) retry_fcntl( FIL__, __LINE__, sock, F_SETFD, 1 );
354 
355   if ( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
356 		  (void *) &flag, sizeof(flag)) < 0 )
357     {
358       errnum = errno;
359       sh_xfer_printerr (_("syslog setsockopt SO_REUSEADDR"),
360 			   errnum, 514, __LINE__);
361       return -1;
362     }
363 
364 #if defined(SO_BSDCOMPAT)
365   if ( setsockopt(sock, SOL_SOCKET, SO_BSDCOMPAT,
366 		  (void *) &flag, sizeof(flag)) < 0 )
367     {
368       errnum = errno;
369       sh_xfer_printerr (_("syslog setsockopt SO_BSDCOMPAT"),
370 			   errnum, 514, __LINE__);
371       return -1;
372     }
373 #endif
374 
375   res = bind(sock, sa, salen);
376 
377   if ( res < 0)
378     {
379       errnum = errno;
380       sh_xfer_printerr (_("syslog bind"), errnum, 514, __LINE__);
381       sl_close_fd(FIL__, __LINE__, sock);
382       return -1;
383     }
384   return sock;
385 }
386 
387 /* callerFlag == S_TRUE means override the enable_syslog_socket flag
388  */
sh_xfer_create_syslog_socket(int callerFlag)389 int sh_xfer_create_syslog_socket (int callerFlag)
390 {
391   int sock;
392 
393 #if defined(USE_IPVX)
394   struct addrinfo *ai;
395   struct addrinfo *p;
396   struct addrinfo hints;
397 #else
398   struct sockaddr_in addr;
399   int addrlen      = sizeof(addr);
400 #endif
401 
402   SL_ENTER(_("sh_xfer_create_syslog_socket"));
403 
404   if (callerFlag == S_FALSE)
405     {
406       if (enable_syslog_socket == S_FALSE && sh_xfer_syslog_sock_n > 0)
407 	{
408 	  /* user does not wish to use this facility
409 	   */
410 	  TPT(( 0, FIL__, __LINE__, _("msg=<close syslog socket>\n")));
411 	  for (sock = 0; sock < sh_xfer_syslog_sock_n; ++sock)
412 	    {
413 	      sl_close_fd(FIL__, __LINE__, sh_xfer_syslog_sock[sock]);
414 	      sh_xfer_syslog_sock[0] = -1;
415 	    }
416 	}
417       SL_RETURN((-1), _("sh_xfer_create_syslog_socket"));
418     }
419 
420   sh_xfer_printerr (NULL, 0, 514, __LINE__);
421 
422 #if !defined(USE_IPVX)
423 
424   memset(&addr, 0, sizeof(addr));
425   addr.sin_family      = AF_INET;
426   addr.sin_port        = htons(514);
427 
428   sock = do_syslog_socket(AF_INET, SOCK_DGRAM, 0,
429 			  (struct sockaddr *) &addr, addrlen);
430 
431   if (sock >= 0) {
432     sh_xfer_syslog_sock[0] = sock;
433     sh_xfer_syslog_sock_n  = 1;
434   }
435 
436 #else
437   memset (&hints, 0, sizeof (hints));
438   hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
439   hints.ai_socktype = SOCK_DGRAM;
440   if (getaddrinfo (NULL, "syslog", &hints, &ai) != 0)
441     {
442       int errnum = errno;
443       sh_xfer_printerr (_("getaddrinfo"), errnum, 514, __LINE__);
444       SL_RETURN((-1), _("sh_xfer_create_syslog_socket"));
445     }
446 
447   p = ai;
448 
449   while (p != NULL && sh_xfer_syslog_sock_n < SH_SOCKMAX)
450     {
451       sock = do_syslog_socket(p->ai_family, p->ai_socktype, p->ai_protocol,
452 			      p->ai_addr, p->ai_addrlen);
453 
454       if (sock >= 0) {
455 	if (sh_xfer_syslog_sock_n < SH_SOCKMAX) {
456 	  sh_xfer_syslog_sock[sh_xfer_syslog_sock_n] = sock;
457 	  ++sh_xfer_syslog_sock_n;
458 	}
459 	else {
460 	  sl_close_fd (FIL__, __LINE__, sock);
461 	}
462       } else if (sock == -1) {
463 	freeaddrinfo (ai);
464 	goto end;
465       }
466       p = p->ai_next;
467     }
468   freeaddrinfo (ai);
469 
470  end:
471 #endif
472   if (sh_xfer_syslog_sock_n > 1)
473     SH_MINSOCK += (sh_xfer_syslog_sock_n - 1);
474 
475   SL_RETURN((sh_xfer_syslog_sock_n), _("sh_xfer_create_syslog_socket"));
476 }
477 /* #ifdef INET_SYSLOG */
478 #endif
479 
480 /* #ifdef SH_WITH_SERVER */
481 #endif
482