2
* Copyright (C) 2007-2009 Sourcefire, Inc.
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License version 2 as
8
* published by the Free Software Foundation.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22
#include "clamav-config.h"
39
#include <sys/socket.h>
42
#include <sys/types.h>
45
#ifdef HAVE_SYS_SELECT_H
46
#include <sys/select.h>
49
#if defined(USE_SYSLOG) && !defined(C_AIX)
54
#include "libclamav/others.h"
55
#include "libclamav/str.h"
63
pthread_mutex_t logg_mutex = PTHREAD_MUTEX_INITIALIZER;
64
pthread_mutex_t mdprintf_mutex = PTHREAD_MUTEX_INITIALIZER;
67
#if defined(C_LINUX) && defined(HAVE_LIBINTL_H)
71
#define gettext_noop(s) s
72
#define _(s) gettext(s)
73
#define N_(s) gettext_noop(s)
84
short int logg_verbose = 0, logg_nowarn = 0, logg_lock = 1, logg_time = 0, logg_foreground = 1, logg_noflush = 0, logg_rotate = 0;
86
const char *logg_file = NULL;
87
#if defined(USE_SYSLOG) && !defined(C_AIX)
91
short int mprintf_disabled = 0, mprintf_verbose = 0, mprintf_quiet = 0,
92
mprintf_stdout = 0, mprintf_nowarn = 0, mprintf_send_timeout = 100;
94
#define ARGLEN(args, str, len) \
96
size_t arglen = 1, i; \
98
va_start(args, str); \
100
for(i = 0; i < len - 1; i++) { \
101
if(str[i] == '%') { \
104
pt = va_arg(args, char *); \
106
arglen += strlen(pt); \
109
va_arg(args, double); \
113
va_arg(args, long); \
127
int mdprintf(int desc, const char *str, ...)
130
char buffer[512], *abuffer = NULL, *buff;
131
int bytes, todo, ret=0;
134
ARGLEN(args, str, len);
135
if(len <= sizeof(buffer)) {
136
len = sizeof(buffer);
139
abuffer = malloc(len);
141
len = sizeof(buffer);
148
bytes = vsnprintf(buff, len, str, args);
153
if(len > sizeof(buffer))
157
if((size_t) bytes >= len)
161
#ifdef CL_THREAD_SAFE
162
/* make sure we don't mix sends from multiple threads,
163
* important for IDSESSION */
164
pthread_mutex_lock(&mdprintf_mutex);
167
ret = send(desc, buff, bytes, 0);
170
if (errno != EWOULDBLOCK)
172
/* didn't send anything yet */
173
#ifdef CL_THREAD_SAFE
174
pthread_mutex_unlock(&mdprintf_mutex);
177
tv.tv_usec = mprintf_send_timeout*1000;
182
ret = select(desc+1, NULL, &wfds, NULL, &tv);
183
} while (ret < 0 && errno == EINTR);
184
#ifdef CL_THREAD_SAFE
185
pthread_mutex_lock(&mdprintf_mutex);
197
#ifdef CL_THREAD_SAFE
198
pthread_mutex_unlock(&mdprintf_mutex);
201
if(len > sizeof(buffer))
204
return ret < 0 ? -1 : bytes;
207
static int rename_logg(STATBUF *sb)
210
size_t rotate_file_len;
216
fprintf(logg_fp, "Log size = %zu, max = %zu\n", sb->st_size, logg_size);
217
fprintf(logg_fp, "WARNING: Log size limit met but log file rotation turned off. Forcing log file rotation anyways.\n");
223
rotate_file_len = strlen(logg_file) + sizeof("-YYYY-MM-DD_HH:MM:SS");
224
rotate_file = calloc(1, rotate_file_len + 1);
227
fprintf(logg_fp, "Need to rotate log file due to size but ran out of memory.\n");
233
if (!localtime_r(&t, &tmp)) {
235
fprintf(logg_fp, "Need to rotate log file due to size but could not get local time.\n");
241
strcpy(rotate_file, logg_file);
242
strftime(rotate_file+strlen(rotate_file), rotate_file_len-strlen(rotate_file), "-%Y%m%d_%H%M%S", &tmp);
249
if (rename(logg_file, rotate_file)) {
258
static int logg_open(void)
264
if(CLAMSTAT(logg_file, &sb) != -1)
265
if(sb.st_size > logg_size)
266
if (rename_logg(&sb))
273
void logg_close(void)
275
#if defined(USE_SYSLOG) && !defined(C_AIX)
280
#ifdef CL_THREAD_SAFE
281
pthread_mutex_lock(&logg_mutex);
287
#ifdef CL_THREAD_SAFE
288
pthread_mutex_unlock(&logg_mutex);
297
* # - normal, not foreground (logfile and syslog only)
302
* Default Foreground LogVerbose Debug Syslog
303
* ! yes mprintf yes yes LOG_ERR
304
* ^ yes mprintf yes yes LOG_WARNING
305
* ~ yes mprintf yes yes LOG_INFO
306
* # yes no yes yes LOG_INFO
307
* * no mprintf yes yes LOG_DEBUG
308
* $ no mprintf no yes LOG_DEBUG
309
* none yes mprintf yes yes LOG_INFO
311
int logg(const char *str, ...)
314
char buffer[1025], *abuffer = NULL, *buff;
322
if ((*str == '$' && logg_verbose < 2) ||
323
(*str == '*' && !logg_verbose))
326
ARGLEN(args, str, len);
327
if(len <= sizeof(buffer)) {
328
len = sizeof(buffer);
331
abuffer = malloc(len);
333
len = sizeof(buffer);
340
vsnprintf(buff, len, str, args);
344
#ifdef CL_THREAD_SAFE
345
pthread_mutex_lock(&logg_mutex);
350
if(!logg_fp && logg_file) {
351
old_umask = umask(0037);
352
if((logg_fp = fopen(logg_file, "at")) == NULL) {
354
#ifdef CL_THREAD_SAFE
355
pthread_mutex_unlock(&logg_mutex);
357
printf("ERROR: Can't open %s in append mode (check permissions!).\n", logg_file);
358
if(len > sizeof(buffer))
361
} else umask(old_umask);
365
memset(&fl, 0, sizeof(fl));
367
if(fcntl(fileno(logg_fp), F_SETLK, &fl) == -1) {
369
if(errno == EOPNOTSUPP)
370
printf("WARNING: File locking not supported (NFS?)\n");
374
#ifdef CL_THREAD_SAFE
375
pthread_mutex_unlock(&logg_mutex);
377
printf("ERROR: %s is locked by another process\n", logg_file);
378
if(len > sizeof(buffer))
388
char flush = !logg_noflush;
389
/* Need to avoid logging time for verbose messages when logverbose
390
is not set or we get a bunch of timestamps in the log without
392
if(logg_time && ((*buff != '*') || logg_verbose)) {
395
cli_ctime(&currtime, timestr, sizeof(timestr));
396
/* cut trailing \n */
397
timestr[strlen(timestr)-1] = '\0';
398
fprintf(logg_fp, "%s -> ", timestr);
402
fprintf(logg_fp, "ERROR: %s", buff + 1);
404
} else if(*buff == '^') {
406
fprintf(logg_fp, "WARNING: %s", buff + 1);
408
} else if(*buff == '*' || *buff == '$') {
409
fprintf(logg_fp, "%s", buff + 1);
410
} else if(*buff == '#' || *buff == '~') {
411
fprintf(logg_fp, "%s", buff + 1);
413
fprintf(logg_fp, "%s", buff);
419
if(logg_foreground) {
424
#if defined(USE_SYSLOG) && !defined(C_AIX)
428
syslog(LOG_ERR, "%s", buff + 1);
429
} else if(buff[0] == '^') {
431
syslog(LOG_WARNING, "%s", buff + 1);
432
} else if(buff[0] == '*' || buff[0] == '$') {
433
syslog(LOG_DEBUG, "%s", buff + 1);
434
} else if(buff[0] == '#' || buff[0] == '~') {
435
syslog(LOG_INFO, "%s", buff + 1);
436
} else syslog(LOG_INFO, "%s", buff);
441
#ifdef CL_THREAD_SAFE
442
pthread_mutex_unlock(&logg_mutex);
445
if(len > sizeof(buffer))
450
void mprintf(const char *str, ...)
454
char buffer[512], *abuffer = NULL, *buff;
465
* @ - error with logging
470
* ERROR WARNING STANDARD
471
* normal stderr stderr stdout
473
* verbose stderr stderr stdout
478
ARGLEN(args, str, len);
479
if(len <= sizeof(buffer)) {
480
len = sizeof(buffer);
483
abuffer = malloc(len);
485
len = sizeof(buffer);
492
vsnprintf(buff, len, str, args);
498
int tmplen = len + 1;
499
wchar_t *tmpw = malloc(tmplen*sizeof(wchar_t));
502
if(!MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, buff, -1, tmpw, tmplen)) {
506
/* FIXME CHECK IT'S REALLY UTF8 */
507
nubuff = (char *)malloc(tmplen);
512
if(!WideCharToMultiByte(CP_OEMCP, 0, tmpw, -1, nubuff, tmplen, NULL, NULL)) {
518
if(len > sizeof(buffer))
520
abuffer = buff = nubuff;
521
len = sizeof(buffer) + 1;
527
fprintf(fd, "ERROR: %s", &buff[1]);
528
} else if(buff[0] == '@') {
531
fprintf(fd, "ERROR: %s", &buff[1]);
532
} else if(!mprintf_quiet) {
534
if(!mprintf_nowarn) {
537
fprintf(fd, "WARNING: %s", &buff[1]);
539
} else if(buff[0] == '*') {
541
fprintf(fd, "%s", &buff[1]);
542
} else if(buff[0] == '~') {
543
fprintf(fd, "%s", &buff[1]);
544
} else fprintf(fd, "%s", buff);
550
if(len > sizeof(buffer))
559
#if defined(USE_SYSLOG) && !defined(C_AIX)
560
static const struct facstruct facilitymap[] = {
562
{ "LOG_AUTH", LOG_AUTH },
565
{ "LOG_AUTHPRIV", LOG_AUTHPRIV },
568
{ "LOG_CRON", LOG_CRON },
571
{ "LOG_DAEMON", LOG_DAEMON },
574
{ "LOG_FTP", LOG_FTP },
577
{ "LOG_KERN", LOG_KERN },
580
{ "LOG_LPR", LOG_LPR },
583
{ "LOG_MAIL", LOG_MAIL },
586
{ "LOG_NEWS", LOG_NEWS },
589
{ "LOG_AUTH", LOG_AUTH },
592
{ "LOG_SYSLOG", LOG_SYSLOG },
595
{ "LOG_USER", LOG_USER },
598
{ "LOG_UUCP", LOG_UUCP },
601
{ "LOG_LOCAL0", LOG_LOCAL0 },
604
{ "LOG_LOCAL1", LOG_LOCAL1 },
607
{ "LOG_LOCAL2", LOG_LOCAL2 },
610
{ "LOG_LOCAL3", LOG_LOCAL3 },
613
{ "LOG_LOCAL4", LOG_LOCAL4 },
616
{ "LOG_LOCAL5", LOG_LOCAL5 },
619
{ "LOG_LOCAL6", LOG_LOCAL6 },
622
{ "LOG_LOCAL7", LOG_LOCAL7 },
627
int logg_facility(const char *name)
631
for(i = 0; facilitymap[i].name; i++)
632
if(!strcmp(facilitymap[i].name, name))
633
return facilitymap[i].code;