source: trunk/src/sh_err_console.c

Last change on this file was 559, checked in by katerina, 13 months ago

Fix for ticket #448 (logging to unix domain socket).

File size: 11.3 KB
Line 
1/* SAMHAIN file system integrity testing                                   */
2/* Copyright (C) 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
24#include "samhain.h"
25#include "sh_error.h"
26#include "sh_utils.h"
27#include "sh_sem.h"
28
29#undef  FIL__
30#define FIL__  _("sh_err_console.c")
31
32#include <stdio.h>
33#include <sys/types.h>
34#include <fcntl.h>
35#include <sys/stat.h>
36#include <unistd.h>
37#include <signal.h>
38#include <sys/socket.h>
39#include <sys/un.h>
40
41extern int  OnlyStderr;
42 
43#if !defined(O_NONBLOCK)
44#if defined(O_NDELAY)
45#define O_NONBLOCK  O_NDELAY
46#else
47#define O_NONBLOCK  0
48#endif
49#endif
50
51#if defined(WITH_MESSAGE_QUEUE)
52
53#if defined(HAVE_SYS_MSG_H)
54
55#include <sys/ipc.h>
56#include <sys/msg.h>
57
58#if !defined(EIDRM)
59#define EIDRM (EINVAL)
60#endif
61
62struct sh_msgbuf {
63  long mtype;
64  char mtext[1];  /* <-- sizeof(mtext) will be  1+MY_MAX_MSG */
65};
66
67static int msgq_enabled = S_FALSE;
68
69/* The identifier of the message queue
70 */
71static int msgid = -1;
72
73/* Open the SysV message queue, creating it when neccesary
74 */
75static int open_queue(void)
76{
77  key_t            key;
78#if defined(WITH_TPT)
79  char errbuf[SH_ERRBUF_SIZE];
80#endif
81
82  SL_ENTER(_("open_queue"));
83
84  /* get key
85   */
86  key = ftok (DEFAULT_DATAROOT, '#');
87
88  if (key == (key_t) -1)
89    {
90      TPT(( 0, FIL__, __LINE__, _("msg=<ftok: %s> errno=<%d>\n"), 
91            sh_error_message(errno, errbuf, sizeof(errbuf)), errno));
92      SL_RETURN(-1, _("open_queue"));
93    }
94
95  /* get message identifier
96   */
97  msgid = msgget (key, IPC_CREAT|MESSAGE_QUEUE_MODE);
98
99  if (msgid < 0)
100    {
101      TPT(( 0, FIL__, __LINE__, _("msg=<msgget: %s> errno=<%d>\n"), 
102            sh_error_message(errno, errbuf, sizeof(errbuf)), errno));
103      SL_RETURN(-1, _("open_queue"));
104    }
105
106  SL_RETURN(0, _("open_queue"));
107}
108
109/* Close the SysV message queue and/or semaphore
110 */
111void close_ipc (void)
112{
113  if (msgid != (-1))
114    (void) msgctl (msgid, IPC_RMID, NULL);
115  sh_sem_close();
116  return;
117}
118
119/* Enable the message queue
120 */
121int enable_msgq(const char * foo)
122{
123  int i;
124
125  SL_ENTER(_("enable_msgq"));
126  i = sh_util_flagval(foo, &msgq_enabled);
127  SL_RETURN(i, _("enable_msgq"));
128}
129
130#define MY_MAX_MSG    1022
131
132static void remove_message()
133{
134  int rc;
135  struct {
136    long    mtype;       /* Message type. */
137    char    mtext[128];  /* Message text. */
138  } recv_msg;
139
140  recv_msg.mtype = 1;
141  do {
142    rc = msgrcv(msgid, &recv_msg, sizeof(recv_msg.mtext), 1, 
143                MSG_NOERROR|IPC_NOWAIT);
144  } while (rc < 0 && errno == EINTR);
145
146  memset(&recv_msg, 0, sizeof(recv_msg));
147  return;
148}
149
150static int push_message_queue (const char * msg)
151{
152  struct sh_msgbuf*   recv_msg = NULL;
153  int              rc       = -1;
154  static int       status   = -1;
155  int              count    = 0;
156#if defined(WITH_TPT)
157  char errbuf[SH_ERRBUF_SIZE];
158#endif
159
160  SL_ENTER(_("push_message_queue"));
161
162  if (msgq_enabled == -1)
163    {
164      TPT(( 0, FIL__, __LINE__, _("msg=<msg_queue not enabled>\n"))); 
165      SL_RETURN(0, _("push_message_queue"));
166    }
167
168  if (status < 0)
169    {
170      TPT(( 0, FIL__, __LINE__, _("msg=<msg_queue not open>\n"))); 
171      status = open_queue();
172    }
173
174  if (status < 0)
175    {
176      TPT(( 0, FIL__, __LINE__, _("msg=<open_queue() failed>\n"))); 
177      SL_RETURN(-1, _("push_message_queue"));
178    }
179
180  /* struct msgbuf {
181   *   long mtype;
182   *   char mtext[1];  <-- sizeof(mtext) will be  1+MY_MAX_MSG
183   * } */
184
185  recv_msg = (struct sh_msgbuf*) SH_ALLOC(sizeof(struct sh_msgbuf)+MY_MAX_MSG);
186  recv_msg->mtype = 1;
187  sl_strlcpy (recv_msg->mtext, msg, MY_MAX_MSG+1);
188
189  count = 0;
190
191 send_it:
192
193  if (count > 1)
194    {
195      memset(recv_msg, 0, MY_MAX_MSG+1);
196      SH_FREE(recv_msg);
197      SL_RETURN(-1, _("push_message_queue"));
198    }
199
200  do { errno = 0;
201    rc = msgsnd(msgid, recv_msg, strlen(recv_msg->mtext)+1, IPC_NOWAIT);
202
203    if (rc == -1 && errno == EAGAIN)
204      remove_message();
205  } while (rc < 0 && (errno == EINTR && errno == EAGAIN));
206 
207  if (rc == -1 && errno != EAGAIN) 
208    {
209      /* EIDRM is not in OpenBSD */
210      if (errno == EINVAL || errno == EIDRM) {
211        TPT(( 0, FIL__, __LINE__, _("msg=<msg_queue not open>\n"))); 
212        status = open_queue();
213        if (status == 0) {
214          ++count;
215          goto send_it; }
216      } else {
217        TPT(( 0, FIL__, __LINE__, _("msg=<msgsnd: %s> errno=<%d>\n"), 
218              sh_error_message(errno, errbuf, sizeof(errbuf)), errno));
219        memset(recv_msg, 0, MY_MAX_MSG+1);
220        SH_FREE(recv_msg);
221        SL_RETURN(-1, _("push_message_queue"));
222      }
223    }
224
225  memset(recv_msg, 0, MY_MAX_MSG+1);
226  SH_FREE(recv_msg);
227
228  SL_RETURN(0, _("push_message_queue"));
229}
230/* if defined(HAVE_SYS_MSG_H) */
231#else
232
233#error **********************************************
234#error
235#error The sys/msg.h header was not found,
236#error cannot compile with --enable-message-queue
237#error
238#error **********************************************
239
240#endif
241
242#else /* no message queue */
243
244void close_ipc() { sh_sem_close(); return; }
245
246#endif
247
248static int count_dev_console = 0;
249
250typedef enum { SH_LOG_UNIX, SH_LOG_OTHER, SH_LOG_INDEF } sh_log_devtype;
251
252static sh_log_devtype dt[2] = { SH_LOG_INDEF, SH_LOG_INDEF };
253static int            st[2] = { SOCK_DGRAM, SOCK_DGRAM };
254
255void reset_count_dev_console(void)
256{
257  count_dev_console = 0;
258  dt[0] = SH_LOG_INDEF;
259  dt[1] = SH_LOG_INDEF;
260  st[0] = SOCK_DGRAM;
261  st[1] = SOCK_DGRAM;
262 
263  return;
264}
265
266/* ---- Set the console device. ----
267 */
268int sh_log_set_console (const char * address)
269{
270  SL_ENTER(_("sh_log_set_console"));
271  if (address != NULL && count_dev_console < 2 
272      && sl_strlen(address) < SH_PATHBUF)
273    {
274      if (count_dev_console == 0)
275        (void) sl_strlcpy (sh.srvcons.name, address, SH_PATHBUF);
276      else
277        (void) sl_strlcpy (sh.srvcons.alt,  address, SH_PATHBUF);
278
279      ++count_dev_console;
280      SL_RETURN(0, _("sh_log_set_console"));
281    }
282  SL_RETURN((-1), _("sh_log_set_console"));
283}
284
285#if defined(WITH_TRACE) || defined(WITH_TPT)
286char *  sh_log_console_name (void)
287{
288  if (sh.srvcons.name[0] == '\0' ||
289      0 == strcmp(sh.srvcons.name, _("NULL")))
290    return (_("/dev/console"));
291  return sh.srvcons.name;
292}
293#endif
294
295#ifndef STDERR_FILENO
296#define STDERR_FILENO   2
297#endif
298
299static int  find_socktype(const char * name)
300{
301#ifdef SOCK_SEQPACKET
302    int socktypes[3] = { SOCK_DGRAM, SOCK_SEQPACKET, SOCK_STREAM };
303    int try = 3;
304#else
305    int socktypes[2] = { SOCK_DGRAM, SOCK_STREAM };
306    int try = 2;
307#endif
308    int i;
309    for (i = 0; i < try; ++i) {
310        struct sockaddr_un addr;
311        int fd;
312   
313        if ( (fd = socket(AF_UNIX, socktypes[i], 0)) == -1) {
314            return -1;
315        }
316        memset(&addr, 0, sizeof(addr));
317        addr.sun_family = AF_UNIX;
318        sl_strlcpy(addr.sun_path, name, sizeof(addr.sun_path));
319        if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == 0) {
320            close(fd);
321            return socktypes[i];
322        }
323        close(fd);
324    }
325    return -1;
326}
327
328int sh_log_console_open (const char * name, int slot)
329{
330  int fd = -1;
331
332  if (dt[slot] == SH_LOG_INDEF)
333    {
334      struct stat sb;
335      if (retry_stat(FIL__, __LINE__, name, &sb) == 0)
336        {
337          if ((sb.st_mode & S_IFMT) == S_IFSOCK)
338            {
339              dt[slot] = SH_LOG_UNIX;
340              st[slot] = find_socktype(name);
341              if (st[slot] == -1) {
342                sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
343                   _("Could not determine socket type."), 
344                   name);
345              }
346            }
347          else
348            dt[slot] = SH_LOG_OTHER;
349        }
350    }
351     
352  if (dt[slot] == SH_LOG_OTHER) {
353    fd = open ( name, O_WRONLY|O_APPEND|O_NOCTTY|O_NONBLOCK);
354  }
355  else if (dt[slot] == SH_LOG_UNIX && st[slot] != -1) {
356    struct sockaddr_un addr;
357   
358    if ( (fd = socket(AF_UNIX, st[slot], 0)) == -1) {
359          char ebuf[SH_ERRBUF_SIZE];
360          int  errnum = errno;
361          sh_error_handle ((-1), FIL__, __LINE__, errnum, MSG_E_SUBGEN,
362            sh_error_message(errnum, ebuf, sizeof(ebuf)), 
363            name);
364      return -1;
365    }
366    memset(&addr, 0, sizeof(addr));
367    addr.sun_family = AF_UNIX;
368    sl_strlcpy(addr.sun_path, name, sizeof(addr.sun_path));
369    if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
370          char ebuf[SH_ERRBUF_SIZE];
371          int  errnum = errno;
372          sh_error_handle ((-1), FIL__, __LINE__, errnum, MSG_E_SUBGEN,
373            sh_error_message(errnum, ebuf, sizeof(ebuf)),
374            name);
375      return -1;
376    }
377  }
378  return fd;
379}
380
381/* ---- Print out a message. ----
382 */
383int  sh_log_console (const /*@null@*/char *errmsg)
384{
385  static int service_failure[2] = { 0, 0};
386  int    fd[2] = { -1, -1};
387  int    cc;
388  size_t len;
389  int    ccMax = 1;
390  int    retval = -1;
391  /* static int logkey_seen = 0; */
392  int    error;
393  static int blockMe = 0;
394  int    val_return;
395
396  SL_ENTER(_("sh_log_console"));
397
398  if (errmsg == NULL || blockMe == 1)
399    {
400      SL_RETURN(0, _("sh_log_console"));
401    }
402  else
403    blockMe = 1;
404
405
406#ifdef WITH_MESSAGE_QUEUE
407  if (0 != push_message_queue (errmsg))
408    {
409      TPT(( 0, FIL__, __LINE__, _("msg=<push_message_queue() failed>\n"))); 
410    }
411#endif
412
413  if (sh.flag.isdaemon == S_FALSE || OnlyStderr == S_TRUE)
414    {
415      len = strlen(errmsg);
416      do {
417        val_return = write(STDERR_FILENO, errmsg, len);
418      } while (val_return < 0 && errno == EINTR); 
419      do {
420        val_return = write(STDERR_FILENO, "\n", 1);
421      } while (val_return < 0 && errno == EINTR); 
422      /*
423       * fprintf (stderr, "%s\n", errmsg);
424       */
425      blockMe = 0;
426      SL_RETURN(0, _("sh_log_console"));
427    }
428
429  /* --- daemon && initialized ---
430   */
431  if ( OnlyStderr == S_FALSE ) 
432    {
433      fd[0] = sh_log_console_open ( sh.srvcons.name, 0);
434
435      if (sh.srvcons.alt[0] != '\0')
436        {
437          fd[1] = sh_log_console_open (sh.srvcons.alt, 1);
438          ccMax = 2;
439        }
440
441      for (cc = 0; cc < ccMax; ++cc)
442        {
443     
444          if (fd[cc] < 0 && service_failure[cc] == 0)
445            {
446              error = errno;
447              sh_error_handle ((-1), FIL__, __LINE__, error, MSG_SRV_FAIL,
448                               _("console"), 
449                               (cc == 0) ? sh.srvcons.name : sh.srvcons.alt);
450              service_failure[cc] = 1;
451            }
452
453          if (fd[cc] >= 0)
454            {
455              do {
456                val_return = write(fd[cc], errmsg, strlen(errmsg));
457              } while (val_return < 0 && errno == EINTR);
458              if (dt[cc] != SH_LOG_UNIX || st[cc] == SOCK_STREAM) {
459                do {
460                  val_return = write(fd[cc], "\r\n",              2);
461                } while (val_return < 0 && errno == EINTR);
462              }
463              (void) sl_close_fd(FIL__, __LINE__, fd[cc]);
464              service_failure[cc] = 0;
465            }
466        }
467    }
468  else
469    retval = 0;
470
471  blockMe = 0;
472  SL_RETURN(retval, _("sh_log_console"));
473}
474
475
Note: See TracBrowser for help on using the repository browser.