source: trunk/src/sh_err_console.c

Last change on this file was 559, checked in by katerina, 4 years 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.