source: trunk/src/sh_xfer_syslog.c @ 481

Last change on this file since 481 was 481, checked in by katerina, 6 years ago

Enhancements and fixes for tickets #374, #375, #376, #377, #378, and #379.

File size: 11.7 KB
RevLine 
[481]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
60extern void sh_xfer_printerr(char * str, int errnum, unsigned int port, int line);
61extern int sh_xfer_syslog_sock[SH_SOCKMAX];
62extern int sh_xfer_syslog_sock_n;
63extern 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
77typedef struct sh_code {
78        char    *c_name;
79        int     c_val;
80} SH_CODE;
81
82SH_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
154SH_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
195static int enable_syslog_socket = S_FALSE;
196
197int 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
330int set_syslog_active(const char * c)
331{
332  return sh_util_flagval(c, &enable_syslog_socket);
333}
334
335static 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 */
389int 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
Note: See TracBrowser for help on using the repository browser.