summaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'plugins')
-rw-r--r--plugins/imfile/imfile.c5
-rw-r--r--plugins/imklog/Makefile.am12
-rw-r--r--plugins/imklog/bsd.c181
-rw-r--r--plugins/imklog/imklog.c680
-rw-r--r--plugins/imklog/imklog.h32
-rw-r--r--plugins/imklog/ksym.c54
-rw-r--r--plugins/imklog/ksym_mod.c12
-rw-r--r--plugins/imklog/linux.c544
-rw-r--r--plugins/imuxsock/imuxsock.c2
-rw-r--r--plugins/omgssapi/omgssapi.c17
-rw-r--r--plugins/ommail/Makefile.am6
-rw-r--r--plugins/ommail/ommail.c630
-rw-r--r--plugins/omrelp/omrelp.c12
13 files changed, 1585 insertions, 602 deletions
diff --git a/plugins/imfile/imfile.c b/plugins/imfile/imfile.c
index 162cab9f..75e54f04 100644
--- a/plugins/imfile/imfile.c
+++ b/plugins/imfile/imfile.c
@@ -95,7 +95,7 @@ static rsRetVal enqLine(fileInfo_t *pInfo, cstr_t *cstrLine)
MsgSetUxTradMsg(pMsg, (char*)rsCStrGetSzStr(cstrLine));
MsgSetRawMsg(pMsg, (char*)rsCStrGetSzStr(cstrLine));
MsgSetMSG(pMsg, (char*)rsCStrGetSzStr(cstrLine));
- MsgSetHOSTNAME(pMsg, LocalHostName);
+ MsgSetHOSTNAME(pMsg, (char*)LocalHostName);
MsgSetTAG(pMsg, (char*)pInfo->pszTag);
pMsg->iFacility = LOG_FAC(pInfo->iFacility);
pMsg->iSeverity = LOG_PRI(pInfo->iSeverity);
@@ -379,6 +379,9 @@ ENDafterRun
*/
BEGINmodExit
CODESTARTmodExit
+ /* release objects we used */
+ objRelease(datetime, CORE_COMPONENT);
+ objRelease(errmsg, CORE_COMPONENT);
ENDmodExit
diff --git a/plugins/imklog/Makefile.am b/plugins/imklog/Makefile.am
index 11e00962..246b3306 100644
--- a/plugins/imklog/Makefile.am
+++ b/plugins/imklog/Makefile.am
@@ -1,6 +1,16 @@
pkglib_LTLIBRARIES = imklog.la
-imklog_la_SOURCES = imklog.c imklog.h module.h ksym.c ksyms.h ksym_mod.c
+imklog_la_SOURCES = imklog.c imklog.h
+
+# select klog "driver"
+if ENABLE_IMKLOG_BSD
+imklog_la_SOURCES += bsd.c
+endif
+
+if ENABLE_IMKLOG_LINUX
+imklog_la_SOURCES += linux.c module.h ksym.c ksyms.h ksym_mod.c
+endif
+
imklog_la_CPPFLAGS = -I$(top_srcdir) $(pthreads_cflags)
imklog_la_LDFLAGS = -module -avoid-version
imklog_la_LIBADD =
diff --git a/plugins/imklog/bsd.c b/plugins/imklog/bsd.c
new file mode 100644
index 00000000..39b644c0
--- /dev/null
+++ b/plugins/imklog/bsd.c
@@ -0,0 +1,181 @@
+/* klog for BSD, based on the FreeBSD syslogd implementation.
+ *
+ * This contains OS-specific functionality to read the BSD
+ * kernel log. For a general overview, see head comment in
+ * imklog.c.
+ *
+ * Copyright (C) 2008 by Rainer Gerhards for the modifications of
+ * the original FreeBSD sources.
+ *
+ * I would like to express my gratitude to those folks which
+ * layed an important foundation for rsyslog to build on.
+ *
+ * This file is part of rsyslog.
+ *
+ * Rsyslog is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Rsyslog is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Rsyslog. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
+ *
+ * This file is based on earlier work included in the FreeBSD sources. We
+ * integrated it into the rsyslog project. The copyright below applies, and
+ * I also reproduce the original license under which we aquired the code:
+ *
+ * Copyright (c) 1983, 1988, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * If you would like to use the code under the BSD license, you should
+ * aquire your own copy of BSD's syslogd, from which we have taken it. The
+ * code in this file is modified and may only be used under the terms of
+ * the GPLv3+ as specified above.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+
+#include "rsyslog.h"
+#include "imklog.h"
+
+/* globals */
+static int fklog = -1; /* /dev/klog */
+
+#ifndef _PATH_KLOG
+# define _PATH_KLOG "/dev/klog"
+#endif
+
+/* open the kernel log - will be called inside the willRun() imklog
+ * entry point. -- rgerhards, 2008-04-09
+ */
+rsRetVal
+klogWillRun(void)
+{
+ DEFiRet;
+
+ fklog = open(_PATH_KLOG, O_RDONLY, 0);
+ if (fklog < 0) {
+ dbgprintf("can't open %s (%d)\n", _PATH_KLOG, errno);
+ iRet = RS_RET_ERR; // TODO: better error code
+ }
+
+ RETiRet;
+}
+
+
+/* Read /dev/klog while data are available, split into lines.
+ * Contrary to standard BSD syslogd, we do a blocking read. We can
+ * afford this as imklog is running on its own threads. So if we have
+ * a single file, it really doesn't matter if we wait inside a 1-file
+ * select or the read() directly.
+ */
+static void
+readklog(void)
+{
+ char *p, *q, line[MAXLINE + 1];
+ int len, i;
+
+ len = 0;
+ for (;;) {
+ dbgprintf("----------imklog waiting for kernel log line\n");
+ i = read(fklog, line + len, MAXLINE - 1 - len);
+ if (i > 0) {
+ line[i + len] = '\0';
+ } else {
+ if (i < 0 && errno != EINTR && errno != EAGAIN) {
+ imklogLogIntMsg(LOG_ERR,
+ "imklog error %d reading kernel log - shutting down imklog",
+ errno);
+ fklog = -1;
+ }
+ break;
+ }
+
+ for (p = line; (q = strchr(p, '\n')) != NULL; p = q + 1) {
+ *q = '\0';
+ Syslog(LOG_INFO, (uchar*) p);
+ }
+ len = strlen(p);
+ if (len >= MAXLINE - 1) {
+ Syslog(LOG_INFO, (uchar*)p);
+ len = 0;
+ }
+ if (len > 0)
+ memmove(line, p, len + 1);
+ }
+ if (len > 0)
+ Syslog(LOG_INFO, (uchar*)line);
+}
+
+
+/* to be called in the module's AfterRun entry point
+ * rgerhards, 2008-04-09
+ */
+rsRetVal klogAfterRun(void)
+{
+ DEFiRet;
+ if(fklog != -1)
+ close(fklog);
+ RETiRet;
+}
+
+
+
+/* to be called in the module's WillRun entry point, this is the main
+ * "message pull" mechanism.
+ * rgerhards, 2008-04-09
+ */
+rsRetVal klogLogKMsg(void)
+{
+ DEFiRet;
+ readklog();
+ RETiRet;
+}
+
+
+/* provide the (system-specific) default facility for internal messages
+ * rgerhards, 2008-04-14
+ */
+int
+klogFacilIntMsg(void)
+{
+ return LOG_SYSLOG;
+}
diff --git a/plugins/imklog/imklog.c b/plugins/imklog/imklog.c
index bfea8c6f..c6fb1592 100644
--- a/plugins/imklog/imklog.c
+++ b/plugins/imklog/imklog.c
@@ -1,14 +1,24 @@
-/* The kernel log input module for Linux. This file heavily
- * borrows from the klogd daemon provided by the sysklogd project.
- * Many thanks for this piece of software.
+/* The kernel log module.
+ *
+ * This is an abstracted module. As Linux and BSD kernel log is conceptually the
+ * same, we do not do different input plugins for them but use
+ * imklog in both cases, just with different "backend drivers" for
+ * the different platforms. This also enables a rsyslog.conf to
+ * be used on multiple platforms without the need to take care of
+ * what the kernel log is coming from.
+ *
+ * See platform-specific files (e.g. linux.c, bsd.c) in the plugin's
+ * working directory. For other systems with similar kernel logging
+ * functionality, no new input plugin shall be written but rather a
+ * driver be developed for imklog. Please note that imklog itself is
+ * mostly concerned with handling the interface. Any real action happens
+ * in the drivers, as things may be pretty different on different
+ * platforms.
*
* Please note that this file replaces the klogd daemon that was
* also present in pre-v3 versions of rsyslog.
*
- * I have begun to convert this to an input module on 2007-12-17.
- * IMPORTANT: more than a single instance is currently not supported. This
- * needs to be revisited once the config file and input module interface
- * supports multiple instances!
+ * Copyright (C) 2008 by Rainer Gerhards and Adiscon GmbH
*
* This file is part of rsyslog.
*
@@ -29,559 +39,157 @@
*/
#include "config.h"
#include "rsyslog.h"
-#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
-#include <signal.h>
#include <string.h>
-#include <pthread.h>
+#include <stdarg.h>
+#include <ctype.h>
+
#include "syslogd.h"
#include "cfsysline.h"
-#include "template.h"
+#include "obj.h"
#include "msg.h"
#include "module-template.h"
+#include "datetime.h"
#include "imklog.h"
MODULE_TYPE_INPUT
/* Module static data */
DEF_IMOD_STATIC_DATA
+DEFobjCurrIf(datetime)
/* configuration settings TODO: move to instance data? */
int dbgPrintSymbols = 0; /* this one is extern so the helpers can access it! */
-static int symbols_twice = 0;
-static int use_syscall = 0;
-static int symbol_lookup = 1;
+int symbols_twice = 0;
+int use_syscall = 0;
+int symbol_lookup = 1;
+int bPermitNonKernel = 0; /* permit logging of messages not having LOG_KERN facility */
+int iFacilIntMsg; /* the facility to use for internal messages (set by driver) */
/* TODO: configuration for the following directives must be implemented. It
* was not done yet because we either do not yet have a config handler for
* that type or I thought it was acceptable to push it to a later stage when
* I gained more handson experience with the input module interface (and the
* changes resulting from that). -- rgerhards, 2007-12-20
*/
-static char *symfile = NULL;
-static int console_log_level = -1;
-
-
-/* Includes. */
-#include <unistd.h>
-#include <errno.h>
-#include <sys/fcntl.h>
-#include <sys/stat.h>
-
-#if HAVE_TIME_H
-# include <time.h>
-#endif
-
-#include <stdarg.h>
-#include <paths.h>
-#include "ksyms.h"
-
-#define __LIBRARY__
-#include <unistd.h>
-
-
-#if !defined(__GLIBC__)
-# define __NR_ksyslog __NR_syslog
-_syscall3(int,ksyslog,int, type, char *, buf, int, len);
-#else
-#include <sys/klog.h>
-#define ksyslog klogctl
-#endif
-
-
-
-#ifndef _PATH_KLOG
-#define _PATH_KLOG "/proc/kmsg"
-#endif
-
-#define LOG_BUFFER_SIZE 4096
-#define LOG_LINE_LENGTH 1000
-
-static int kmsg;
-static char log_buffer[LOG_BUFFER_SIZE];
-
-static enum LOGSRC {none, proc, kernel} logsrc;
-
+char *symfile = NULL;
+int console_log_level = -1;
-/* Function prototypes. */
-extern int ksyslog(int type, char *buf, int len);
-
-
-/* Write a message to the message queue.
- * returns -1 if it fails, something else otherwise
+/* enqueue the the kernel message into the message queue.
+ * The provided msg string is not freed - thus must be done
+ * by the caller.
+ * rgerhards, 2008-04-12
*/
-static rsRetVal writeSyslogV(int iPRI, const char *szFmt, va_list va)
+static rsRetVal
+enqMsg(uchar *msg, uchar* pszTag, int iFacility, int iSeverity)
{
DEFiRet;
- int iChars;
- int iLen;
- time_t tNow;
- char msgBuf[2048]; /* we use the same size as sysklogd to remain compatible */
-
- assert(szFmt != NULL);
-
- /* build the message */
- time(&tNow);
- /* we can use sprintf safely below, because we know the size of the constants.
- * By doing so, we save some cpu cycles and code complexity (for unnecessary
- * error checking).
- */
- iLen = sprintf(msgBuf, "<%d>%.15s kernel: ", iPRI, ctime(&tNow) + 4);
-
- iChars = vsnprintf(msgBuf + iLen, sizeof(msgBuf) / sizeof(char) - iLen, szFmt, va);
-
- /* here we must create our message object and supply it to the message queue
- */
- CHKiRet(parseAndSubmitMessage(LocalHostName, msgBuf, strlen(msgBuf), MSG_DONT_PARSE_HOSTNAME, NOFLAG, eFLOWCTL_LIGHT_DELAY));
+ msg_t *pMsg;
+
+ assert(msg != NULL);
+ assert(pszTag != NULL);
+
+ CHKiRet(msgConstruct(&pMsg));
+ MsgSetFlowControlType(pMsg, eFLOWCTL_LIGHT_DELAY);
+ MsgSetUxTradMsg(pMsg, (char*)msg);
+ MsgSetRawMsg(pMsg, (char*)msg);
+ MsgSetMSG(pMsg, (char*)msg);
+ MsgSetHOSTNAME(pMsg, (char*)LocalHostName);
+ MsgSetTAG(pMsg, (char*)pszTag);
+ pMsg->iFacility = LOG_FAC(iFacility);
+ pMsg->iSeverity = LOG_PRI(iSeverity);
+ pMsg->bParseHOSTNAME = 0;
+ datetime.getCurrTime(&(pMsg->tTIMESTAMP)); /* use the current time! */
+ CHKiRet(submitMsg(pMsg));
finalize_it:
RETiRet;
}
-/* And now the same with variable arguments */
-static int writeSyslog(int iPRI, const char *szFmt, ...)
-{
- int iRet;
- va_list va;
-
- assert(szFmt != NULL);
- va_start(va, szFmt);
- iRet = writeSyslogV(iPRI, szFmt, va);
- va_end(va);
-
- return(iRet);
-}
-
-rsRetVal Syslog(int priority, char *fmt, ...) __attribute__((format(printf,2, 3)));
-rsRetVal Syslog(int priority, char *fmt, ...)
+/* parse the PRI from a kernel message. At least BSD seems to have
+ * non-kernel messages inside the kernel log...
+ * Expected format: "<pri>". piPri is only valid if the function
+ * successfully returns. If there was a proper pri ppSz is advanced to the
+ * position right after ">".
+ * rgerhards, 2008-04-14
+ */
+static rsRetVal
+parsePRI(uchar **ppSz, int *piPri)
{
DEFiRet;
- va_list ap;
- char *argl;
-
- /* Output using syslog. */
- if (!strcmp(fmt, "%s")) {
- va_start(ap, fmt);
- argl = va_arg(ap, char *);
- if (argl[0] == '<' && argl[1] && argl[2] == '>') {
- switch ( argl[1] )
- {
- case '0':
- priority = LOG_EMERG;
- break;
- case '1':
- priority = LOG_ALERT;
- break;
- case '2':
- priority = LOG_CRIT;
- break;
- case '3':
- priority = LOG_ERR;
- break;
- case '4':
- priority = LOG_WARNING;
- break;
- case '5':
- priority = LOG_NOTICE;
- break;
- case '6':
- priority = LOG_INFO;
- break;
- case '7':
- default:
- priority = LOG_DEBUG;
- }
- argl += 3;
- }
- iRet = writeSyslog(priority, fmt, argl);
- va_end(ap);
- } else {
- va_start(ap, fmt);
- iRet = writeSyslogV(priority, fmt, ap);
- va_end(ap);
- }
-
- RETiRet;
-}
-
-
-static void CloseLogSrc(void)
-{
- /* Turn on logging of messages to console, but only if we had the -c
- * option -- rgerhards, 2007-08-01
- */
- if (console_log_level != -1)
- ksyslog(7, NULL, 0);
-
- /* Shutdown the log sources. */
- switch ( logsrc )
- {
- case kernel:
- ksyslog(0, 0, 0);
- Syslog(LOG_INFO, "Kernel logging (ksyslog) stopped.");
- break;
- case proc:
- close(kmsg);
- Syslog(LOG_INFO, "Kernel logging (proc) stopped.");
- break;
- case none:
- break;
- }
+ int i;
+ uchar *pSz;
- return;
-}
+ assert(ppSz != NULL);
+ pSz = *ppSz;
+ assert(pSz != NULL);
+ assert(piPri != NULL);
+ if(*pSz != '<' || !isdigit(*(pSz+1)))
+ ABORT_FINALIZE(RS_RET_INVALID_PRI);
-static enum LOGSRC GetKernelLogSrc(void)
-{
- auto struct stat sb;
-
- /* Set level of kernel console messaging.. */
- if ( (console_log_level != -1) &&
- (ksyslog(8, NULL, console_log_level) < 0) &&
- (errno == EINVAL) )
- {
- /*
- * An invalid arguement error probably indicates that
- * a pre-0.14 kernel is being run. At this point we
- * issue an error message and simply shut-off console
- * logging completely.
- */
- Syslog(LOG_WARNING, "Cannot set console log level - disabling "
- "console output.");
+ ++pSz;
+ i = 0;
+ while(isdigit(*pSz)) {
+ i = i * 10 + *pSz - '0';
}
- /*
- * First do a stat to determine whether or not the proc based
- * file system is available to get kernel messages from.
- */
- if ( use_syscall ||
- ((stat(_PATH_KLOG, &sb) < 0) && (errno == ENOENT)) )
- {
- /* Initialize kernel logging. */
- ksyslog(1, NULL, 0);
- Syslog(LOG_INFO, "imklogd %s, log source = ksyslog "
- "started.", VERSION);
- return(kernel);
- }
+ if(*pSz != '>')
+ ABORT_FINALIZE(RS_RET_INVALID_PRI);
- if ( (kmsg = open(_PATH_KLOG, O_RDONLY)) < 0 )
- {
- char sz[512];
- snprintf(sz, sizeof(sz), "imklog: Cannot open proc file system, %d - %s.\n", errno, strerror(errno));
- logmsgInternal(LOG_SYSLOG|LOG_ERR, sz, ADDDATE);
- ksyslog(7, NULL, 0); /* TODO: check this, implement more */
- return(none);
- }
+ /* OK, we have a valid PRI */
+ *piPri = i;
- Syslog(LOG_INFO, "imklog %s, log source = %s started.", \
- VERSION, _PATH_KLOG);
- return(proc);
+finalize_it:
+ RETiRet;
}
-/* Copy characters from ptr to line until a char in the delim
- * string is encountered or until min( space, len ) chars have
- * been copied.
- *
- * Returns the actual number of chars copied.
+/* log an imklog-internal message
+ * rgerhards, 2008-04-14
*/
-static int copyin( char *line, int space,
- const char *ptr, int len,
- const char *delim )
+rsRetVal imklogLogIntMsg(int priority, char *fmt, ...)
{
- auto int i;
- auto int count;
-
- count = len < space ? len : space;
+ DEFiRet;
+ va_list ap;
+ uchar msgBuf[2048]; /* we use the same size as sysklogd to remain compatible */
+ uchar *pLogMsg;
- for(i=0; i<count && !strchr(delim, *ptr); i++ ) {
- *line++ = *ptr++;
- }
+ va_start(ap, fmt);
+ vsnprintf((char*)msgBuf, sizeof(msgBuf) / sizeof(char), fmt, ap);
+ pLogMsg = msgBuf;
+ va_end(ap);
- return(i);
-}
+ iRet = enqMsg((uchar*)pLogMsg, (uchar*) ((iFacilIntMsg == LOG_KERN) ? "kernel:" : "imklog:"),
+ iFacilIntMsg, LOG_PRI(priority));
-/*
- * Messages are separated by "\n". Messages longer than
- * LOG_LINE_LENGTH are broken up.
- *
- * Kernel symbols show up in the input buffer as : "[<aaaaaa>]",
- * where "aaaaaa" is the address. These are replaced with
- * "[symbolname+offset/size]" in the output line - symbolname,
- * offset, and size come from the kernel symbol table.
- *
- * If a kernel symbol happens to fall at the end of a message close
- * in length to LOG_LINE_LENGTH, the symbol will not be expanded.
- * (This should never happen, since the kernel should never generate
- * messages that long.
- *
- * To preserve the original addresses, lines containing kernel symbols
- * are output twice. Once with the symbols converted and again with the
- * original text. Just in case somebody wants to run their own Oops
- * analysis on the syslog, e.g. ksymoops.
- */
-static void LogLine(char *ptr, int len)
-{
- enum parse_state_enum {
- PARSING_TEXT,
- PARSING_SYMSTART, /* at < */
- PARSING_SYMBOL,
- PARSING_SYMEND /* at ] */
- };
-
- static char line_buff[LOG_LINE_LENGTH];
-
- static char *line =line_buff;
- static enum parse_state_enum parse_state = PARSING_TEXT;
- static int space = sizeof(line_buff)-1;
-
- static char *sym_start; /* points at the '<' of a symbol */
-
- auto int delta = 0; /* number of chars copied */
- auto int symbols_expanded = 0; /* 1 if symbols were expanded */
- auto int skip_symbol_lookup = 0; /* skip symbol lookup on this pass */
- auto char *save_ptr = ptr; /* save start of input line */
- auto int save_len = len; /* save length at start of input line */
-
- while( len > 0 )
- {
- if( space == 0 ) /* line buffer is full */
- {
- /*
- ** Line too long. Start a new line.
- */
- *line = 0; /* force null terminator */
-
- dbgprintf("Line buffer full:\n");
- dbgprintf("\tLine: %s\n", line);
-
- Syslog( LOG_INFO, "%s", line_buff );
- line = line_buff;
- space = sizeof(line_buff)-1;
- parse_state = PARSING_TEXT;
- symbols_expanded = 0;
- skip_symbol_lookup = 0;
- save_ptr = ptr;
- save_len = len;
- }
-
- switch( parse_state )
- {
- case PARSING_TEXT:
- delta = copyin( line, space, ptr, len, "\n[" );
- line += delta;
- ptr += delta;
- space -= delta;
- len -= delta;
-
- if( space == 0 || len == 0 )
- {
- break; /* full line_buff or end of input buffer */
- }
-
- if( *ptr == '\0' ) /* zero byte */
- {
- ptr++; /* skip zero byte */
- space -= 1;
- len -= 1;
-
- break;
- }
-
- if( *ptr == '\n' ) /* newline */
- {
- ptr++; /* skip newline */
- space -= 1;
- len -= 1;
-
- *line = 0; /* force null terminator */
- Syslog( LOG_INFO, "%s", line_buff );
- line = line_buff;
- space = sizeof(line_buff)-1;
- if (symbols_twice) {
- if (symbols_expanded) {
- /* reprint this line without symbol lookup */
- symbols_expanded = 0;
- skip_symbol_lookup = 1;
- ptr = save_ptr;
- len = save_len;
- }
- else
- {
- skip_symbol_lookup = 0;
- save_ptr = ptr;
- save_len = len;
- }
- }
- break;
- }
- if( *ptr == '[' ) /* possible kernel symbol */
- {
- *line++ = *ptr++;
- space -= 1;
- len -= 1;
- if (!skip_symbol_lookup)
- parse_state = PARSING_SYMSTART; /* at < */
- break;
- }
- /* Now that line_buff is no longer fed to *printf as format
- * string, '%'s are no longer "dangerous".
- */
- break;
-
- case PARSING_SYMSTART:
- if( *ptr != '<' )
- {
- parse_state = PARSING_TEXT; /* not a symbol */
- break;
- }
-
- /*
- ** Save this character for now. If this turns out to
- ** be a valid symbol, this char will be replaced later.
- ** If not, we'll just leave it there.
- */
-
- sym_start = line; /* this will point at the '<' */
-
- *line++ = *ptr++;
- space -= 1;
- len -= 1;
- parse_state = PARSING_SYMBOL; /* symbol... */
- break;
-
- case PARSING_SYMBOL:
- delta = copyin( line, space, ptr, len, ">\n[" );
- line += delta;
- ptr += delta;
- space -= delta;
- len -= delta;
- if( space == 0 || len == 0 )
- {
- break; /* full line_buff or end of input buffer */
- }
- if( *ptr != '>' )
- {
- parse_state = PARSING_TEXT;
- break;
- }
-
- *line++ = *ptr++; /* copy the '>' */
- space -= 1;
- len -= 1;
-
- parse_state = PARSING_SYMEND;
-
- break;
-
- case PARSING_SYMEND:
- if( *ptr != ']' )
- {
- parse_state = PARSING_TEXT; /* not a symbol */
- break;
- }
-
- /*
- ** It's really a symbol! Replace address with the
- ** symbol text.
- */
- {
- auto int sym_space;
-
- unsigned long value;
- auto struct symbol sym;
- auto char *symbol;
-
- *(line-1) = 0; /* null terminate the address string */
- value = strtoul(sym_start+1, (char **) 0, 16);
- *(line-1) = '>'; /* put back delim */
-
- if ( !symbol_lookup || (symbol = LookupSymbol(value, &sym)) == (char *)0 )
- {
- parse_state = PARSING_TEXT;
- break;
- }
-
- /*
- ** verify there is room in the line buffer
- */
- sym_space = space + ( line - sym_start );
- if( (unsigned) sym_space < strlen(symbol) + 30 ) /*(30 should be overkill)*/
- {
- parse_state = PARSING_TEXT; /* not enough space */
- break;
- }
-
- delta = sprintf( sym_start, "%s+%d/%d]",
- symbol, sym.offset, sym.size );
-
- space = sym_space + delta;
- line = sym_start + delta;
- symbols_expanded = 1;
- }
- ptr++;
- len--;
- parse_state = PARSING_TEXT;
- break;
-
- default: /* Can't get here! */
- parse_state = PARSING_TEXT;
-
- }
- }
-
- return;
+ RETiRet;
}
-static void LogKernelLine(void)
+/* log a kernel message
+ * rgerhards, 2008-04-14
+ */
+rsRetVal Syslog(int priority, uchar *pMsg)
{
- auto int rdcnt;
+ DEFiRet;
+ rsRetVal localRet;
- /*
- * Zero-fill the log buffer. This should cure a multitude of
- * problems with klogd logging the tail end of the message buffer
- * which will contain old messages. Then read the kernel log
- * messages into this fresh buffer.
- */
- memset(log_buffer, '\0', sizeof(log_buffer));
- if ( (rdcnt = ksyslog(2, log_buffer, sizeof(log_buffer)-1)) < 0 )
- {
- char sz[512];
- if(errno == EINTR)
- return;
- snprintf(sz, sizeof(sz), "imklog: Error return from sys_sycall: %d - %s\n", errno, strerror(errno));
- logmsgInternal(LOG_SYSLOG|LOG_ERR, sz, ADDDATE);
- }
- else
- LogLine(log_buffer, rdcnt);
- return;
-}
+ /* Output using syslog */
+ localRet = parsePRI(&pMsg, &priority);
+ if(localRet != RS_RET_INVALID_PRI && localRet != RS_RET_OK)
+ FINALIZE;
+ /* if we don't get the pri, we use whatever we were supplied */
+ /* ignore non-kernel messages if not permitted */
+ if(bPermitNonKernel == 0 && LOG_FAC(priority) != LOG_KERN)
+ FINALIZE; /* silently ignore */
-static void LogProcLine(void)
-{
- auto int rdcnt;
+ iRet = enqMsg((uchar*)pMsg, (uchar*) "kernel:", LOG_FAC(priority), LOG_PRI(priority));
- /*
- * Zero-fill the log buffer. This should cure a multitude of
- * problems with klogd logging the tail end of the message buffer
- * which will contain old messages. Then read the kernel messages
- * from the message pseudo-file into this fresh buffer.
- */
- memset(log_buffer, '\0', sizeof(log_buffer));
- if ( (rdcnt = read(kmsg, log_buffer, sizeof(log_buffer)-1)) < 0 )
- {
- if ( errno == EINTR )
- return;
- Syslog(LOG_ERR, "Cannot read proc file system: %d - %s.", errno, strerror(errno));
- }
- else
- LogLine(log_buffer, rdcnt);
-
- return;
+finalize_it:
+ RETiRet;
}
@@ -592,64 +200,32 @@ CODESTARTrunInput
* right into the sleep below.
*/
while(!pThrd->bShallStop) {
- /* we do not need to handle the RS_RET_TERMINATE_NOW case any
- * special because we just need to terminate. This may be different
- * if a cleanup is needed. But for now, we can just use CHKiRet().
- * rgerhards, 2007-12-17
+ /* klogLogKMsg() waits for the next kernel message, obtains it
+ * and then submits it to the rsyslog main queue.
+ * rgerhards, 2008-04-09
*/
- switch ( logsrc )
- {
- case kernel:
- LogKernelLine();
- break;
- case proc:
- LogProcLine();
- break;
- case none:
- /* TODO: We need to handle this case here somewhat more intelligent
- * This is now at least partly done - code should never reach this point
- * as willRun() already checked for the "none" status -- rgerhards, 2007-12-17
- */
- pause();
- break;
- }
+ CHKiRet(klogLogKMsg());
}
- RETiRet;
+finalize_it:
ENDrunInput
BEGINwillRun
- /* Initialize this module. If that fails, we tell the engine we don't like to run */
- /* Determine where kernel logging information is to come from. */
- logsrc = GetKernelLogSrc();
- if(logsrc == none) {
- iRet = RS_RET_NO_KERNEL_LOGSRC;
- } else {
- if (symbol_lookup) {
- symbol_lookup = (InitKsyms(symfile) == 1);
- symbol_lookup |= InitMsyms();
- if (symbol_lookup == 0) {
- Syslog(LOG_WARNING, "cannot find any symbols, turning off symbol lookups\n");
- }
- }
- }
CODESTARTwillRun
+ iRet = klogWillRun();
ENDwillRun
BEGINafterRun
CODESTARTafterRun
- /* cleanup here */
- if(logsrc != none)
- CloseLogSrc();
-
- DeinitKsyms();
- DeinitMsyms();
+ iRet = klogAfterRun();
ENDafterRun
BEGINmodExit
CODESTARTmodExit
+ /* release objects we used */
+ objRelease(datetime, CORE_COMPONENT);
ENDmodExit
@@ -665,6 +241,8 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a
use_syscall = 0;
symfile = NULL;
symbol_lookup = 1;
+ bPermitNonKernel = 0;
+ iFacilIntMsg = klogFacilIntMsg();
return RS_RET_OK;
}
@@ -672,17 +250,17 @@ BEGINmodInit()
CODESTARTmodInit
*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
CODEmodInit_QueryRegCFSLineHdlr
+ CHKiRet(objUse(datetime, CORE_COMPONENT));
+
+ iFacilIntMsg = klogFacilIntMsg();
+
CHKiRet(omsdRegCFSLineHdlr((uchar *)"debugprintkernelsymbols", 0, eCmdHdlrBinary, NULL, &dbgPrintSymbols, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogsymbollookup", 0, eCmdHdlrBinary, NULL, &symbol_lookup, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogsymbolstwice", 0, eCmdHdlrBinary, NULL, &symbols_twice, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogusesyscallinterface", 0, eCmdHdlrBinary, NULL, &use_syscall, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogpermitnonkernelfacility", 0, eCmdHdlrBinary, NULL, &bPermitNonKernel, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"kloginternalmsgfacility", 0, eCmdHdlrFacility, NULL, &iFacilIntMsg, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
ENDmodInit
-/*
- * Local variables:
- * c-indent-level: 8
- * c-basic-offset: 8
- * tab-width: 8
- * End:
- * vi:set ai:
+/* vim:set ai:
*/
diff --git a/plugins/imklog/imklog.h b/plugins/imklog/imklog.h
index 71525a79..a37ecc9e 100644
--- a/plugins/imklog/imklog.h
+++ b/plugins/imklog/imklog.h
@@ -2,8 +2,10 @@
* These are the definitions for the klog message generation module.
*
* File begun on 2007-12-17 by RGerhards
+ * Major change: 2008-04-09: switched to a driver interface for
+ * several platforms
*
- * Copyright 2007 Rainer Gerhards and Adiscon GmbH.
+ * Copyright 2007-2008 Rainer Gerhards and Adiscon GmbH.
*
* This file is part of rsyslog.
*
@@ -28,9 +30,33 @@
#include "rsyslog.h"
#include "syslogd.h"
-/* global variables */
+/* interface to "drivers"
+ * the platform specific drivers must implement these entry points. Only one
+ * driver may be active at any given time, thus we simply rely on the linker
+ * to resolve the addresses.
+ * rgerhards, 2008-04-09
+ */
+rsRetVal klogLogKMsg(void);
+rsRetVal klogWillRun(void);
+rsRetVal klogAfterRun(void);
+int klogFacilIntMsg(void);
+
+/* the following data members may be accessed by the "drivers"
+ * I admit this is not the cleanest way to doing things, but I honestly
+ * believe it is appropriate for the job that needs to be done.
+ * rgerhards, 2008-04-09
+ */
+extern int symbols_twice;
+extern int use_syscall;
+extern int symbol_lookup;
+extern char *symfile;
+extern int console_log_level;
extern int dbgPrintSymbols;
+/* the functions below may be called by the drivers */
+rsRetVal imklogLogIntMsg(int priority, char *fmt, ...) __attribute__((format(printf,2, 3)));
+rsRetVal Syslog(int priority, uchar *msg);
+
/* prototypes */
extern int InitKsyms(char *);
extern void DeinitKsyms(void);
@@ -38,8 +64,6 @@ extern int InitMsyms(void);
extern void DeinitMsyms(void);
extern char * ExpandKadds(char *, char *);
extern void SetParanoiaLevel(int);
-extern void vsyslog(int pri, const char *fmt, va_list ap);
-rsRetVal Syslog(int priority, char *fmt, ...) __attribute__((format(printf,2, 3)));
#endif /* #ifndef IMKLOG_H_INCLUDED */
/* vi:set ai:
diff --git a/plugins/imklog/ksym.c b/plugins/imklog/ksym.c
index b7d5903e..1c2af124 100644
--- a/plugins/imklog/ksym.c
+++ b/plugins/imklog/ksym.c
@@ -185,18 +185,18 @@ extern int InitKsyms(char *mapfile)
if ( mapfile != (char *) 0 ) {
if ( (sym_file = fopen(mapfile, "r")) == (FILE *) 0 )
{
- Syslog(LOG_WARNING, "Cannot open map file: %s.", mapfile);
+ imklogLogIntMsg(LOG_WARNING, "Cannot open map file: %s.", mapfile);
return(0);
}
} else {
if ( (mapfile = FindSymbolFile()) == (char *) 0 ) {
- Syslog(LOG_WARNING, "Cannot find map file.");
+ imklogLogIntMsg(LOG_WARNING, "Cannot find map file.");
dbgprintf("Cannot find map file.\n");
return(0);
}
if ( (sym_file = fopen(mapfile, "r")) == (FILE *) 0 ) {
- Syslog(LOG_WARNING, "Cannot open map file.");
+ imklogLogIntMsg(LOG_WARNING, "Cannot open map file.");
dbgprintf("Cannot open map file.\n");
return(0);
}
@@ -213,7 +213,7 @@ extern int InitKsyms(char *mapfile)
*/
while ( !feof(sym_file) ) {
if ( fscanf(sym_file, "%lx %c %s\n", &address, &type, sym) != 3 ) {
- Syslog(LOG_ERR, "Error in symbol table input (#1).");
+ imklogLogIntMsg(LOG_ERR, "Error in symbol table input (#1).");
fclose(sym_file);
return(0);
}
@@ -221,7 +221,7 @@ extern int InitKsyms(char *mapfile)
dbgprintf("Address: %lx, Type: %c, Symbol: %s\n", address, type, sym);
if ( AddSymbol(address, sym) == 0 ) {
- Syslog(LOG_ERR, "Error adding symbol - %s.", sym);
+ imklogLogIntMsg(LOG_ERR, "Error adding symbol - %s.", sym);
fclose(sym_file);
return(0);
}
@@ -231,19 +231,19 @@ extern int InitKsyms(char *mapfile)
}
- Syslog(LOG_INFO, "Loaded %d symbols from %s.", num_syms, mapfile);
+ imklogLogIntMsg(LOG_INFO, "Loaded %d symbols from %s.", num_syms, mapfile);
switch(version) {
case -1:
- Syslog(LOG_WARNING, "Symbols do not match kernel version.");
+ imklogLogIntMsg(LOG_WARNING, "Symbols do not match kernel version.");
num_syms = 0;
break;
case 0:
- Syslog(LOG_WARNING, "Cannot verify that symbols match kernel version.");
+ imklogLogIntMsg(LOG_WARNING, "Cannot verify that symbols match kernel version.");
break;
case 1:
- Syslog(LOG_INFO, "Symbols match kernel version %s.", vstring);
+ imklogLogIntMsg(LOG_INFO, "Symbols match kernel version %s.", vstring);
break;
}
@@ -296,12 +296,12 @@ static char *FindSymbolFile(void)
**mf = system_maps;
auto struct utsname utsname;
- static char symfile[100];
+ static char mysymfile[100];
auto FILE *sym_file = (FILE *) 0;
if ( uname(&utsname) < 0 ) {
- Syslog(LOG_ERR, "Cannot get kernel version information.");
+ imklogLogIntMsg(LOG_ERR, "Cannot get kernel version information.");
return(0);
}
@@ -309,19 +309,19 @@ static char *FindSymbolFile(void)
for(mf = system_maps; *mf != (char *) 0 && file == (char *) 0; ++mf) {
- snprintf(symfile, sizeof(symfile), "%s-%s", *mf, utsname.release);
- dbgprintf("Trying %s.\n", symfile);
- if ( (sym_file = fopen(symfile, "r")) != (FILE *) 0 ) {
- if (CheckMapVersion(symfile) == 1)
- file = symfile;
+ snprintf(mysymfile, sizeof(mysymfile), "%s-%s", *mf, utsname.release);
+ dbgprintf("Trying %s.\n", mysymfile);
+ if ( (sym_file = fopen(mysymfile, "r")) != (FILE *) 0 ) {
+ if (CheckMapVersion(mysymfile) == 1)
+ file = mysymfile;
fclose(sym_file);
}
if (sym_file == (FILE *) 0 || file == (char *) 0) {
- sprintf (symfile, "%s", *mf);
- dbgprintf("Trying %s.\n", symfile);
- if ( (sym_file = fopen(symfile, "r")) != (FILE *) 0 ) {
- if (CheckMapVersion(symfile) == 1)
- file = symfile;
+ sprintf (mysymfile, "%s", *mf);
+ dbgprintf("Trying %s.\n", mysymfile);
+ if ( (sym_file = fopen(mysymfile, "r")) != (FILE *) 0 ) {
+ if (CheckMapVersion(mysymfile) == 1)
+ file = mysymfile;
fclose(sym_file);
}
}
@@ -410,13 +410,13 @@ static int CheckVersion(char *version)
* version level.
*/
if ( uname(&utsname) < 0 ) {
- Syslog(LOG_ERR, "Cannot get kernel version information.");
+ imklogLogIntMsg(LOG_ERR, "Cannot get kernel version information.");
return(0);
}
dbgprintf("Comparing kernel %s with symbol table %s.\n", utsname.release, vstring);
if ( sscanf (utsname.release, "%d.%d.%d", &major, &minor, &patch) < 3 ) {
- Syslog(LOG_ERR, "Kernel send bogus release string `%s'.", utsname.release);
+ imklogLogIntMsg(LOG_ERR, "Kernel send bogus release string `%s'.", utsname.release);
return(0);
}
@@ -470,12 +470,12 @@ static int CheckMapVersion(char *fname)
* now need to search this file and look for version
* information.
*/
- Syslog(LOG_INFO, "Inspecting %s", fname);
+ imklogLogIntMsg(LOG_INFO, "Inspecting %s", fname);
version = 0;
while ( !feof(sym_file) && (version == 0) ) {
if ( fscanf(sym_file, "%lx %c %s\n", &address, &type, sym) != 3 ) {
- Syslog(LOG_ERR, "Error in symbol table input (#2).");
+ imklogLogIntMsg(LOG_ERR, "Error in symbol table input (#2).");
fclose(sym_file);
return(0);
}
@@ -487,7 +487,7 @@ static int CheckMapVersion(char *fname)
switch ( version ) {
case -1:
- Syslog(LOG_ERR, "Symbol table has incorrect version number.\n");
+ imklogLogIntMsg(LOG_ERR, "Symbol table has incorrect version number.\n");
break;
case 0:
dbgprintf("No version information found.\n");
@@ -684,7 +684,7 @@ extern char *ExpandKadds(char *line, char *el)
*/
if ( i_am_paranoid &&
(strstr(line, "Oops:") != (char *) 0) && !InitMsyms() )
- Syslog(LOG_WARNING, "Cannot load kernel module symbols.\n");
+ imklogLogIntMsg(LOG_WARNING, "Cannot load kernel module symbols.\n");
/*
diff --git a/plugins/imklog/ksym_mod.c b/plugins/imklog/ksym_mod.c
index 11535a5f..bef810b4 100644
--- a/plugins/imklog/ksym_mod.c
+++ b/plugins/imklog/ksym_mod.c
@@ -158,10 +158,10 @@ extern int InitMsyms(void)
if ( ksyms == NULL ) {
if ( errno == ENOENT )
- Syslog(LOG_INFO, "No module symbols loaded - "
+ imklogLogIntMsg(LOG_INFO, "No module symbols loaded - "
"kernel modules not enabled.\n");
else
- Syslog(LOG_ERR, "Error loading kernel symbols " \
+ imklogLogIntMsg(LOG_ERR, "Error loading kernel symbols " \
"- %s\n", strerror(errno));
fclose(ksyms);
return(0);
@@ -201,9 +201,9 @@ extern int InitMsyms(void)
}
if ( rtn == 0 )
- Syslog(LOG_INFO, "No module symbols loaded.");
+ imklogLogIntMsg(LOG_INFO, "No module symbols loaded.");
else
- Syslog(LOG_INFO, "Loaded %d %s from %d module%s", rtn, \
+ imklogLogIntMsg(LOG_INFO, "Loaded %d %s from %d module%s", rtn, \
(rtn == 1) ? "symbol" : "symbols", \
num_modules, (num_modules == 1) ? "." : "s.");
@@ -296,7 +296,7 @@ struct Module *AddModule(module)
if ( sym_array_modules == NULL )
{
- Syslog(LOG_WARNING, "Cannot allocate Module array.\n");
+ imklogLogIntMsg(LOG_WARNING, "Cannot allocate Module array.\n");
return NULL;
}
mp = sym_array_modules;
@@ -308,7 +308,7 @@ struct Module *AddModule(module)
if ( mp == NULL )
{
- Syslog(LOG_WARNING, "Cannot allocate Module array.\n");
+ imklogLogIntMsg(LOG_WARNING, "Cannot allocate Module array.\n");
return NULL;
}
diff --git a/plugins/imklog/linux.c b/plugins/imklog/linux.c
new file mode 100644
index 00000000..a742a456
--- /dev/null
+++ b/plugins/imklog/linux.c
@@ -0,0 +1,544 @@
+/* klog for linux, based on the FreeBSD syslogd implementation.
+ *
+ * This contains OS-specific functionality to read the BSD
+ * kernel log. For a general overview, see head comment in
+ * imklog.c.
+ *
+ * This file heavily borrows from the klogd daemon provided by
+ * the sysklogd project. Many thanks for this piece of software.
+ *
+ * This file is part of rsyslog.
+ *
+ * Rsyslog is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Rsyslog is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Rsyslog. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
+*/
+#include "config.h"
+#include "rsyslog.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <signal.h>
+#include <string.h>
+#include <pthread.h>
+#include "syslogd.h"
+#include "cfsysline.h"
+#include "template.h"
+#include "msg.h"
+#include "module-template.h"
+#include "imklog.h"
+
+
+/* Includes. */
+#include <unistd.h>
+#include <errno.h>
+#include <sys/fcntl.h>
+#include <sys/stat.h>
+
+#if HAVE_TIME_H
+# include <time.h>
+#endif
+
+#include <stdarg.h>
+#include <paths.h>
+#include "ksyms.h"
+
+#define __LIBRARY__
+#include <unistd.h>
+
+
+#if !defined(__GLIBC__)
+# define __NR_ksyslog __NR_syslog
+_syscall3(int,ksyslog,int, type, char *, buf, int, len);
+#else
+#include <sys/klog.h>
+#define ksyslog klogctl
+#endif
+
+
+
+#ifndef _PATH_KLOG
+#define _PATH_KLOG "/proc/kmsg"
+#endif
+
+#define LOG_BUFFER_SIZE 4096
+#define LOG_LINE_LENGTH 1000
+
+static int kmsg;
+static char log_buffer[LOG_BUFFER_SIZE];
+
+static enum LOGSRC {none, proc, kernel} logsrc;
+
+
+/* Function prototypes. */
+extern int ksyslog(int type, char *buf, int len);
+
+
+static void CloseLogSrc(void)
+{
+ /* Turn on logging of messages to console, but only if we had the -c
+ * option -- rgerhards, 2007-08-01
+ */
+ if (console_log_level != -1)
+ ksyslog(7, NULL, 0);
+
+ /* Shutdown the log sources. */
+ switch ( logsrc )
+ {
+ case kernel:
+ ksyslog(0, 0, 0);
+ imklogLogIntMsg(LOG_INFO, "Kernel logging (ksyslog) stopped.");
+ break;
+ case proc:
+ close(kmsg);
+ imklogLogIntMsg(LOG_INFO, "Kernel logging (proc) stopped.");
+ break;
+ case none:
+ break;
+ }
+
+ return;
+}
+
+
+static enum LOGSRC GetKernelLogSrc(void)
+{
+ auto struct stat sb;
+
+ /* Set level of kernel console messaging.. */
+ if ( (console_log_level != -1) &&
+ (ksyslog(8, NULL, console_log_level) < 0) &&
+ (errno == EINVAL) )
+ {
+ /*
+ * An invalid arguement error probably indicates that
+ * a pre-0.14 kernel is being run. At this point we
+ * issue an error message and simply shut-off console
+ * logging completely.
+ */
+ imklogLogIntMsg(LOG_WARNING, "Cannot set console log level - disabling "
+ "console output.");
+ }
+
+ /*
+ * First do a stat to determine whether or not the proc based
+ * file system is available to get kernel messages from.
+ */
+ if ( use_syscall ||
+ ((stat(_PATH_KLOG, &sb) < 0) && (errno == ENOENT)) )
+ {
+ /* Initialize kernel logging. */
+ ksyslog(1, NULL, 0);
+ imklogLogIntMsg(LOG_INFO, "imklogd %s, log source = ksyslog "
+ "started.", VERSION);
+ return(kernel);
+ }
+
+ if ( (kmsg = open(_PATH_KLOG, O_RDONLY)) < 0 )
+ {
+ char sz[512];
+ snprintf(sz, sizeof(sz), "imklog: Cannot open proc file system, %d - %s.\n", errno, strerror(errno));
+ logmsgInternal(LOG_SYSLOG|LOG_ERR, sz, ADDDATE);
+ ksyslog(7, NULL, 0); /* TODO: check this, implement more */
+ return(none);
+ }
+
+ imklogLogIntMsg(LOG_INFO, "imklog %s, log source = %s started.", VERSION, _PATH_KLOG);
+ return(proc);
+}
+
+
+/* Copy characters from ptr to line until a char in the delim
+ * string is encountered or until min( space, len ) chars have
+ * been copied.
+ *
+ * Returns the actual number of chars copied.
+ */
+static int copyin( uchar *line, int space,
+ const char *ptr, int len,
+ const char *delim )
+{
+ auto int i;
+ auto int count;
+
+ count = len < space ? len : space;
+
+ for(i=0; i<count && !strchr(delim, *ptr); i++ ) {
+ *line++ = *ptr++;
+ }
+
+ return(i);
+}
+
+/*
+ * Messages are separated by "\n". Messages longer than
+ * LOG_LINE_LENGTH are broken up.
+ *
+ * Kernel symbols show up in the input buffer as : "[<aaaaaa>]",
+ * where "aaaaaa" is the address. These are replaced with
+ * "[symbolname+offset/size]" in the output line - symbolname,
+ * offset, and size come from the kernel symbol table.
+ *
+ * If a kernel symbol happens to fall at the end of a message close
+ * in length to LOG_LINE_LENGTH, the symbol will not be expanded.
+ * (This should never happen, since the kernel should never generate
+ * messages that long.
+ *
+ * To preserve the original addresses, lines containing kernel symbols
+ * are output twice. Once with the symbols converted and again with the
+ * original text. Just in case somebody wants to run their own Oops
+ * analysis on the syslog, e.g. ksymoops.
+ */
+static void LogLine(char *ptr, int len)
+{
+ enum parse_state_enum {
+ PARSING_TEXT,
+ PARSING_SYMSTART, /* at < */
+ PARSING_SYMBOL,
+ PARSING_SYMEND /* at ] */
+ };
+
+ static uchar line_buff[LOG_LINE_LENGTH];
+
+ static uchar *line =line_buff;
+ static enum parse_state_enum parse_state = PARSING_TEXT;
+ static int space = sizeof(line_buff)-1;
+
+ static uchar *sym_start; /* points at the '<' of a symbol */
+
+ auto int delta = 0; /* number of chars copied */
+ auto int symbols_expanded = 0; /* 1 if symbols were expanded */
+ auto int skip_symbol_lookup = 0; /* skip symbol lookup on this pass */
+ auto char *save_ptr = ptr; /* save start of input line */
+ auto int save_len = len; /* save length at start of input line */
+
+ while( len > 0 )
+ {
+ if( space == 0 ) /* line buffer is full */
+ {
+ /*
+ ** Line too long. Start a new line.
+ */
+ *line = 0; /* force null terminator */
+
+ dbgprintf("Line buffer full:\n");
+ dbgprintf("\tLine: %s\n", line);
+
+ Syslog(LOG_INFO, line_buff);
+ line = line_buff;
+ space = sizeof(line_buff)-1;
+ parse_state = PARSING_TEXT;
+ symbols_expanded = 0;
+ skip_symbol_lookup = 0;
+ save_ptr = ptr;
+ save_len = len;
+ }
+
+ switch( parse_state )
+ {
+ case PARSING_TEXT:
+ delta = copyin(line, space, ptr, len, "\n[" );
+ line += delta;
+ ptr += delta;
+ space -= delta;
+ len -= delta;
+
+ if( space == 0 || len == 0 )
+ {
+ break; /* full line_buff or end of input buffer */
+ }
+
+ if( *ptr == '\0' ) /* zero byte */
+ {
+ ptr++; /* skip zero byte */
+ space -= 1;
+ len -= 1;
+
+ break;
+ }
+
+ if( *ptr == '\n' ) /* newline */
+ {
+ ptr++; /* skip newline */
+ space -= 1;
+ len -= 1;
+
+ *line = 0; /* force null terminator */
+ Syslog(LOG_INFO, line_buff);
+ line = line_buff;
+ space = sizeof(line_buff)-1;
+ if (symbols_twice) {
+ if (symbols_expanded) {
+ /* reprint this line without symbol lookup */
+ symbols_expanded = 0;
+ skip_symbol_lookup = 1;
+ ptr = save_ptr;
+ len = save_len;
+ }
+ else
+ {
+ skip_symbol_lookup = 0;
+ save_ptr = ptr;
+ save_len = len;
+ }
+ }
+ break;
+ }
+ if( *ptr == '[' ) /* possible kernel symbol */
+ {
+ *line++ = *ptr++;
+ space -= 1;
+ len -= 1;
+ if (!skip_symbol_lookup)
+ parse_state = PARSING_SYMSTART; /* at < */
+ break;
+ }
+ /* Now that line_buff is no longer fed to *printf as format
+ * string, '%'s are no longer "dangerous".
+ */
+ break;
+
+ case PARSING_SYMSTART:
+ if( *ptr != '<' )
+ {
+ parse_state = PARSING_TEXT; /* not a symbol */
+ break;
+ }
+
+ /*
+ ** Save this character for now. If this turns out to
+ ** be a valid symbol, this char will be replaced later.
+ ** If not, we'll just leave it there.
+ */
+
+ sym_start = line; /* this will point at the '<' */
+
+ *line++ = *ptr++;
+ space -= 1;
+ len -= 1;
+ parse_state = PARSING_SYMBOL; /* symbol... */
+ break;
+
+ case PARSING_SYMBOL:
+ delta = copyin( line, space, ptr, len, ">\n[" );
+ line += delta;
+ ptr += delta;
+ space -= delta;
+ len -= delta;
+ if( space == 0 || len == 0 )
+ {
+ break; /* full line_buff or end of input buffer */
+ }
+ if( *ptr != '>' )
+ {
+ parse_state = PARSING_TEXT;
+ break;
+ }
+
+ *line++ = *ptr++; /* copy the '>' */
+ space -= 1;
+ len -= 1;
+
+ parse_state = PARSING_SYMEND;
+
+ break;
+
+ case PARSING_SYMEND:
+ if( *ptr != ']' )
+ {
+ parse_state = PARSING_TEXT; /* not a symbol */
+ break;
+ }
+
+ /*
+ ** It's really a symbol! Replace address with the
+ ** symbol text.
+ */
+ {
+ auto int sym_space;
+
+ unsigned long value;
+ auto struct symbol sym;
+ auto char *symbol;
+
+ *(line-1) = 0; /* null terminate the address string */
+ value = strtoul((char*)(sym_start+1), (char **) 0, 16);
+ *(line-1) = '>'; /* put back delim */
+
+ if ( !symbol_lookup || (symbol = LookupSymbol(value, &sym)) == (char *)0 )
+ {
+ parse_state = PARSING_TEXT;
+ break;
+ }
+
+ /*
+ ** verify there is room in the line buffer
+ */
+ sym_space = space + ( line - sym_start );
+ if( (unsigned) sym_space < strlen(symbol) + 30 ) /*(30 should be overkill)*/
+ {
+ parse_state = PARSING_TEXT; /* not enough space */
+ break;
+ }
+
+ // TODO: sprintf!!!!
+ delta = sprintf( (char*) sym_start, "%s+%d/%d]",
+ symbol, sym.offset, sym.size );
+
+ space = sym_space + delta;
+ line = sym_start + delta;
+ symbols_expanded = 1;
+ }
+ ptr++;
+ len--;
+ parse_state = PARSING_TEXT;
+ break;
+
+ default: /* Can't get here! */
+ parse_state = PARSING_TEXT;
+
+ }
+ }
+
+ return;
+}
+
+
+static void LogKernelLine(void)
+{
+ auto int rdcnt;
+
+ /*
+ * Zero-fill the log buffer. This should cure a multitude of
+ * problems with klogd logging the tail end of the message buffer
+ * which will contain old messages. Then read the kernel log
+ * messages into this fresh buffer.
+ */
+ memset(log_buffer, '\0', sizeof(log_buffer));
+ if ( (rdcnt = ksyslog(2, log_buffer, sizeof(log_buffer)-1)) < 0 )
+ {
+ char sz[512];
+ if(errno == EINTR)
+ return;
+ snprintf(sz, sizeof(sz), "imklog: Error return from sys_sycall: %d - %s\n", errno, strerror(errno));
+ logmsgInternal(LOG_SYSLOG|LOG_ERR, sz, ADDDATE);
+ }
+ else
+ LogLine(log_buffer, rdcnt);
+ return;
+}
+
+
+static void LogProcLine(void)
+{
+ auto int rdcnt;
+
+ /*
+ * Zero-fill the log buffer. This should cure a multitude of
+ * problems with klogd logging the tail end of the message buffer
+ * which will contain old messages. Then read the kernel messages
+ * from the message pseudo-file into this fresh buffer.
+ */
+ memset(log_buffer, '\0', sizeof(log_buffer));
+ if ( (rdcnt = read(kmsg, log_buffer, sizeof(log_buffer)-1)) < 0 ) {
+ if ( errno == EINTR )
+ return;
+ imklogLogIntMsg(LOG_ERR, "Cannot read proc file system: %d - %s.", errno, strerror(errno));
+ } else {
+ LogLine(log_buffer, rdcnt);
+ }
+
+ return;
+}
+
+
+/* to be called in the module's WillRun entry point
+ * rgerhards, 2008-04-09
+ */
+rsRetVal klogLogKMsg(void)
+{
+ DEFiRet;
+ switch(logsrc) {
+ case kernel:
+ LogKernelLine();
+ break;
+ case proc:
+ LogProcLine();
+ break;
+ case none:
+ /* TODO: We need to handle this case here somewhat more intelligent
+ * This is now at least partly done - code should never reach this point
+ * as willRun() already checked for the "none" status -- rgerhards, 2007-12-17
+ */
+ pause();
+ break;
+ }
+ RETiRet;
+}
+
+
+/* to be called in the module's WillRun entry point
+ * rgerhards, 2008-04-09
+ */
+rsRetVal klogWillRun(void)
+{
+ DEFiRet;
+ /* Initialize this module. If that fails, we tell the engine we don't like to run */
+ /* Determine where kernel logging information is to come from. */
+ logsrc = GetKernelLogSrc();
+ if(logsrc == none) {
+ iRet = RS_RET_NO_KERNEL_LOGSRC;
+ } else {
+ if (symbol_lookup) {
+ symbol_lookup = (InitKsyms(symfile) == 1);
+ symbol_lookup |= InitMsyms();
+ if (symbol_lookup == 0) {
+ imklogLogIntMsg(LOG_WARNING, "cannot find any symbols, turning off symbol lookups\n");
+ }
+ }
+ }
+
+ RETiRet;
+}
+
+
+/* to be called in the module's AfterRun entry point
+ * rgerhards, 2008-04-09
+ */
+rsRetVal klogAfterRun(void)
+{
+ DEFiRet;
+ /* cleanup here */
+ if(logsrc != none)
+ CloseLogSrc();
+
+ DeinitKsyms();
+ DeinitMsyms();
+
+ RETiRet;
+}
+
+
+/* provide the (system-specific) default facility for internal messages
+ * rgerhards, 2008-04-14
+ */
+int
+klogFacilIntMsg(void)
+{
+ return LOG_KERN;
+}
+
+
+/* vi:set ai:
+ */
diff --git a/plugins/imuxsock/imuxsock.c b/plugins/imuxsock/imuxsock.c
index 3cdcbf0a..f8798039 100644
--- a/plugins/imuxsock/imuxsock.c
+++ b/plugins/imuxsock/imuxsock.c
@@ -181,7 +181,7 @@ static rsRetVal readSocket(int fd, int bParseHost, int flags)
iRcvd = recv(fd, line, MAXLINE - 1, 0);
dbgprintf("Message from UNIX socket: #%d\n", fd);
if (iRcvd > 0) {
- parseAndSubmitMessage(LocalHostName, line, iRcvd, bParseHost, flags, eFLOWCTL_LIGHT_DELAY);
+ parseAndSubmitMessage((char*)LocalHostName, line, iRcvd, bParseHost, flags, eFLOWCTL_LIGHT_DELAY);
} else if (iRcvd < 0 && errno != EINTR) {
char errStr[1024];
rs_strerror_r(errno, errStr, sizeof(errStr));
diff --git a/plugins/omgssapi/omgssapi.c b/plugins/omgssapi/omgssapi.c
index 9a7e8ab9..8c6a2006 100644
--- a/plugins/omgssapi/omgssapi.c
+++ b/plugins/omgssapi/omgssapi.c
@@ -4,7 +4,7 @@
* NOTE: read comments in module-template.h to understand how this file
* works!
*
- * Copyright 2007 Rainer Gerhards and Adiscon GmbH.
+ * Copyright 2007, 2008 Rainer Gerhards and Adiscon GmbH.
*
* This file is part of rsyslog.
*
@@ -79,7 +79,7 @@ DEFobjCurrIf(gssutil)
DEFobjCurrIf(tcpclt)
typedef struct _instanceData {
- char f_hname[MAXHOSTNAMELEN+1];
+ char *f_hname;
short sock; /* file descriptor */
enum { /* TODO: we shoud revisit these definitions */
eDestFORW,
@@ -162,6 +162,9 @@ CODESTARTfreeInstance
tcpclt.Destruct(&pData->pTCPClt);
if(pData->sock >= 0)
close(pData->sock);
+
+ if(pData->f_hname != NULL)
+ free(pData->f_hname);
ENDfreeInstance
@@ -592,10 +595,11 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1)
/* TODO: make this if go away! */
if(*p == ';') {
*p = '\0'; /* trick to obtain hostname (later)! */
- strcpy(pData->f_hname, (char*) q);
+ CHKmalloc(pData->f_hname = strdup((char*) q));
*p = ';';
- } else
- strcpy(pData->f_hname, (char*) q);
+ } else {
+ CHKmalloc(pData->f_hname = strdup((char*) q));
+ }
/* process template */
CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS,
@@ -701,6 +705,5 @@ CODEmodInit_QueryRegCFSLineHdlr
ENDmodInit
#endif /* #ifdef USE_GSSAPI */
-/*
- * vi:set ai:
+/* vi:set ai:
*/
diff --git a/plugins/ommail/Makefile.am b/plugins/ommail/Makefile.am
new file mode 100644
index 00000000..7e9f5f13
--- /dev/null
+++ b/plugins/ommail/Makefile.am
@@ -0,0 +1,6 @@
+pkglib_LTLIBRARIES = ommail.la
+
+ommail_la_SOURCES = ommail.c
+ommail_la_CPPFLAGS = -I$(top_srcdir) $(pthreads_cflags)
+ommail_la_LDFLAGS = -module -avoid-version
+ommail_la_LIBADD =
diff --git a/plugins/ommail/ommail.c b/plugins/ommail/ommail.c
new file mode 100644
index 00000000..218c73c9
--- /dev/null
+++ b/plugins/ommail/ommail.c
@@ -0,0 +1,630 @@
+/* ommail.c
+ *
+ * This is an implementation of a mail sending output module. So far, we
+ * only support direct SMTP, that is talking to a SMTP server. In the long
+ * term, support for using sendmail should also be implemented. Please note
+ * that the SMTP protocol implementation is a very bare one. We support
+ * RFC821/822 messages, without any authentication and any other nice
+ * features (no MIME, no nothing). It is assumed that proper firewalling
+ * and/or STMP server configuration is used together with this module.
+ *
+ * NOTE: read comments in module-template.h to understand how this file
+ * works!
+ *
+ * File begun on 2008-04-04 by RGerhards
+ *
+ * Copyright 2008 Rainer Gerhards and Adiscon GmbH.
+ *
+ * This file is part of rsyslog.
+ *
+ * Rsyslog is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Rsyslog is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Rsyslog. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
+ */
+#include "config.h"
+#include "rsyslog.h"
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <unistd.h>
+#include <errno.h>
+#include <netdb.h>
+#include <time.h>
+#include <sys/socket.h>
+#include "syslogd.h"
+#include "syslogd-types.h"
+#include "srUtils.h"
+#include "cfsysline.h"
+#include "module-template.h"
+#include "errmsg.h"
+
+MODULE_TYPE_OUTPUT
+
+/* internal structures
+ */
+DEF_OMOD_STATIC_DATA
+DEFobjCurrIf(errmsg)
+
+static uchar *pszSrv = NULL;
+static uchar *pszSrvPort = NULL;
+static uchar *pszFrom = NULL;
+static uchar *pszTo = NULL;
+static uchar *pszSubject = NULL;
+static int bEnableBody = 1; /* should a mail body be generated? (set to 0 eg for SMS gateways) */
+
+typedef struct _instanceData {
+ int iMode; /* 0 - smtp, 1 - sendmail */
+ int bHaveSubject; /* is a subject configured? (if so, it is the second string provided by rsyslog core) */
+ int bEnableBody; /* is a body configured? (if so, it is the second string provided by rsyslog core) */
+ union {
+ struct {
+ uchar *pszSrv;
+ uchar *pszSrvPort;
+ uchar *pszFrom;
+ uchar *pszTo;
+ char RcvBuf[1024]; /* buffer for receiving server responses */
+ size_t lenRcvBuf;
+ size_t iRcvBuf; /* current index into the rcvBuf (buf empty if iRcvBuf == lenRcvBuf) */
+ int sock; /* socket to this server (most important when we do multiple msgs per mail) */
+ } smtp;
+ } md; /* mode-specific data */
+} instanceData;
+
+
+BEGINcreateInstance
+CODESTARTcreateInstance
+ENDcreateInstance
+
+
+BEGINisCompatibleWithFeature
+CODESTARTisCompatibleWithFeature
+ if(eFeat == sFEATURERepeatedMsgReduction)
+ iRet = RS_RET_OK;
+ENDisCompatibleWithFeature
+
+
+BEGINfreeInstance
+CODESTARTfreeInstance
+ if(pData->iMode == 0) {
+ if(pData->md.smtp.pszSrv != NULL)
+ free(pData->md.smtp.pszSrv);
+ if(pData->md.smtp.pszSrvPort != NULL)
+ free(pData->md.smtp.pszSrvPort);
+ if(pData->md.smtp.pszFrom != NULL)
+ free(pData->md.smtp.pszFrom);
+ if(pData->md.smtp.pszTo != NULL)
+ free(pData->md.smtp.pszTo);
+ }
+ENDfreeInstance
+
+
+BEGINdbgPrintInstInfo
+CODESTARTdbgPrintInstInfo
+ printf("mail"); /* TODO: extend! */
+ENDdbgPrintInstInfo
+
+
+/* TCP support code, should probably be moved to net.c or some place else... -- rgerhards, 2008-04-04 */
+
+/* "receive" a character from the remote server. A single character
+ * is returned. Returns RS_RET_NO_MORE_DATA if the server has closed
+ * the connection and RS_RET_IO_ERROR if something goes wrong. This
+ * is a blocking read.
+ * rgerhards, 2008-04-04
+ */
+static rsRetVal
+getRcvChar(instanceData *pData, char *pC)
+{
+ DEFiRet;
+ ssize_t lenBuf;
+ assert(pData != NULL);
+
+ if(pData->md.smtp.iRcvBuf == pData->md.smtp.lenRcvBuf) { /* buffer empty? */
+ /* yes, we need to read the next server response */
+ do {
+ lenBuf = recv(pData->md.smtp.sock, pData->md.smtp.RcvBuf, sizeof(pData->md.smtp.RcvBuf), 0);
+ if(lenBuf == 0) {
+ ABORT_FINALIZE(RS_RET_NO_MORE_DATA);
+ } else if(lenBuf < 0) {
+ if(errno != EAGAIN) {
+ ABORT_FINALIZE(RS_RET_IO_ERROR);
+ }
+ } else {
+ /* good read */
+ pData->md.smtp.iRcvBuf = 0;
+ pData->md.smtp.lenRcvBuf = lenBuf;
+ }
+
+ } while(lenBuf < 1);
+ }
+
+ /* when we reach this point, we have a non-empty buffer */
+ *pC = pData->md.smtp.RcvBuf[pData->md.smtp.iRcvBuf++];
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* close the mail server connection
+ * rgerhards, 2008-04-08
+ */
+static rsRetVal
+serverDisconnect(instanceData *pData)
+{
+ DEFiRet;
+ assert(pData != NULL);
+
+ if(pData->md.smtp.sock != -1) {
+ close(pData->md.smtp.sock);
+ pData->md.smtp.sock = -1;
+ }
+
+ RETiRet;
+}
+
+
+/* open a connection to the mail server
+ * rgerhards, 2008-04-04
+ */
+static rsRetVal
+serverConnect(instanceData *pData)
+{
+ struct addrinfo *res = NULL;
+ struct addrinfo hints;
+ char *smtpPort;
+ char *smtpSrv;
+ char errStr[1024];
+
+ DEFiRet;
+ assert(pData != NULL);
+
+ if(pData->md.smtp.pszSrv == NULL)
+ smtpSrv = "127.0.0.1";
+ else
+ smtpSrv = (char*)pData->md.smtp.pszSrv;
+
+ if(pData->md.smtp.pszSrvPort == NULL)
+ smtpPort = "25";
+ else
+ smtpPort = (char*)pData->md.smtp.pszSrvPort;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC; /* TODO: make configurable! */
+ hints.ai_socktype = SOCK_STREAM;
+ if(getaddrinfo(smtpSrv, smtpPort, &hints, &res) != 0) {
+ dbgprintf("error %d in getaddrinfo\n", errno);
+ ABORT_FINALIZE(RS_RET_IO_ERROR);
+ }
+
+ if((pData->md.smtp.sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1) {
+ dbgprintf("couldn't create send socket, reason %s", rs_strerror_r(errno, errStr, sizeof(errStr)));
+ ABORT_FINALIZE(RS_RET_IO_ERROR);
+ }
+
+ if(connect(pData->md.smtp.sock, res->ai_addr, res->ai_addrlen) != 0) {
+ dbgprintf("create tcp connection failed, reason %s", rs_strerror_r(errno, errStr, sizeof(errStr)));
+ ABORT_FINALIZE(RS_RET_IO_ERROR);
+ }
+
+finalize_it:
+ if(res != NULL)
+ freeaddrinfo(res);
+
+ if(iRet != RS_RET_OK) {
+ if(pData->md.smtp.sock != -1) {
+ close(pData->md.smtp.sock);
+ pData->md.smtp.sock = -1;
+ }
+ }
+
+ RETiRet;
+}
+
+
+/* send text to the server, blocking send */
+static rsRetVal
+Send(int sock, char *msg, size_t len)
+{
+ DEFiRet;
+ size_t offsBuf = 0;
+ ssize_t lenSend;
+
+ assert(msg != NULL);
+
+ if(len == 0) /* it's valid, but does not make much sense ;) */
+ FINALIZE;
+
+ do {
+ lenSend = send(sock, msg + offsBuf, len - offsBuf, 0);
+ if(lenSend == -1) {
+ if(errno != EAGAIN) {
+ dbgprintf("message not (tcp)send, errno %d", errno);
+ ABORT_FINALIZE(RS_RET_TCP_SEND_ERROR);
+ }
+ } else if(lenSend != (ssize_t) len) {
+ offsBuf += len; /* on to next round... */
+ } else {
+ FINALIZE;
+ }
+ } while(1);
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* send body text to the server, blocking send
+ * The body is special in that we must escape a leading dot inside a line
+ */
+static rsRetVal
+bodySend(instanceData *pData, char *msg, size_t len)
+{
+ DEFiRet;
+ char szBuf[2048];
+ size_t iSrc;
+ size_t iBuf = 0;
+ int bHadCR = 0;
+ int bInStartOfLine = 1;
+
+ assert(pData != NULL);
+ assert(msg != NULL);
+
+ for(iSrc = 0 ; iSrc < len ; ++iSrc) {
+ if(iBuf >= sizeof(szBuf) - 1) { /* one is reserved for our extra dot */
+ CHKiRet(Send(pData->md.smtp.sock, szBuf, iBuf));
+ iBuf = 0;
+ }
+ szBuf[iBuf++] = msg[iSrc];
+ switch(msg[iSrc]) {
+ case '\r':
+ bHadCR = 1;
+ break;
+ case '\n':
+ if(bHadCR)
+ bInStartOfLine = 1;
+ bHadCR = 0;
+ break;
+ case '.':
+ if(bInStartOfLine)
+ szBuf[iBuf++] = '.'; /* space is always reserved for this! */
+ /*FALLTHROUGH*/
+ default:
+ bInStartOfLine = 0;
+ bHadCR = 0;
+ break;
+ }
+ }
+
+ if(iBuf > 0) { /* incomplete buffer to send (the *usual* case)? */
+ CHKiRet(Send(pData->md.smtp.sock, szBuf, iBuf));
+ }
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* read response line from server
+ */
+static rsRetVal
+readResponseLn(instanceData *pData, char *pLn, size_t lenLn)
+{
+ DEFiRet;
+ size_t i = 0;
+ char c;
+
+ assert(pData != NULL);
+ assert(pLn != NULL);
+
+ do {
+ CHKiRet(getRcvChar(pData, &c));
+ if(c == '\n')
+ break;
+ if(i < (lenLn - 1)) /* if line is too long, we simply discard the rest */
+ pLn[i++] = c;
+ } while(1);
+ pLn[i] = '\0';
+ dbgprintf("smtp server response: %s\n", pLn); /* do not remove, this is helpful in troubleshooting SMTP probs! */
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* read numerical response code from server and compare it to requried response code.
+ * If they two don't match, return RS_RET_SMTP_ERROR.
+ * rgerhards, 2008-04-07
+ */
+static rsRetVal
+readResponse(instanceData *pData, int *piState, int iExpected)
+{
+ DEFiRet;
+ int bCont;
+ char buf[128];
+
+ assert(pData != NULL);
+ assert(piState != NULL);
+
+ bCont = 1;
+ do {
+ CHKiRet(readResponseLn(pData, buf, sizeof(buf)));
+ /* note: the code below is not 100% clean as we may have received less than 4 characters.
+ * However, as we have a fixed size this will not create a vulnerability. An error will
+ * also most likely be generated, so it is quite acceptable IMHO -- rgerhards, 2008-04-08
+ */
+ if(buf[3] != '-') { /* last or only response line? */
+ bCont = 0;
+ *piState = buf[0] - '0';
+ *piState = *piState * 10 + buf[1] - '0';
+ *piState = *piState * 10 + buf[2] - '0';
+ if(*piState != iExpected)
+ ABORT_FINALIZE(RS_RET_SMTP_ERROR);
+ }
+ } while(bCont);
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* create a timestamp suitable for use with the Date: SMTP body header
+ * rgerhards, 2008-04-08
+ */
+static void
+mkSMTPTimestamp(uchar *pszBuf, size_t lenBuf)
+{
+ time_t tCurr;
+ struct tm tmCurr;
+ static const char szDay[][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
+ static const char szMonth[][4] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+
+ time(&tCurr);
+ gmtime_r(&tCurr, &tmCurr);
+ snprintf((char*)pszBuf, lenBuf, "Date: %s, %2d %s %4d %2d:%02d:%02d UT\r\n", szDay[tmCurr.tm_wday], tmCurr.tm_mday,
+ szMonth[tmCurr.tm_mon], 1900 + tmCurr.tm_year, tmCurr.tm_hour, tmCurr.tm_min, tmCurr.tm_sec);
+}
+
+
+/* send a message via SMTP
+ * rgerhards, 2008-04-04
+ */
+static rsRetVal
+sendSMTP(instanceData *pData, uchar *body, uchar *subject)
+{
+ DEFiRet;
+ int iState; /* SMTP state */
+ uchar szDateBuf[64];
+
+ assert(pData != NULL);
+
+ CHKiRet(serverConnect(pData));
+ CHKiRet(readResponse(pData, &iState, 220));
+
+ CHKiRet(Send(pData->md.smtp.sock, "HELO ", 5));
+ CHKiRet(Send(pData->md.smtp.sock, (char*)LocalHostName, strlen((char*)LocalHostName)));
+ CHKiRet(Send(pData->md.smtp.sock, "\r\n", sizeof("\r\n") - 1));
+ CHKiRet(readResponse(pData, &iState, 250));
+
+ CHKiRet(Send(pData->md.smtp.sock, "MAIL FROM: <", sizeof("MAIL FROM: <") - 1));
+ CHKiRet(Send(pData->md.smtp.sock, (char*)pData->md.smtp.pszFrom, strlen((char*)pData->md.smtp.pszFrom)));
+ CHKiRet(Send(pData->md.smtp.sock, ">\r\n", sizeof(">\r\n") - 1));
+ CHKiRet(readResponse(pData, &iState, 250));
+
+ CHKiRet(Send(pData->md.smtp.sock, "RCPT TO: <", sizeof("RCPT TO: <") - 1));
+ CHKiRet(Send(pData->md.smtp.sock, (char*)pData->md.smtp.pszTo, strlen((char*)pData->md.smtp.pszTo)));
+ CHKiRet(Send(pData->md.smtp.sock, ">\r\n", sizeof(">\r\n") - 1));
+ CHKiRet(readResponse(pData, &iState, 250));
+
+ CHKiRet(Send(pData->md.smtp.sock, "DATA\r\n", sizeof("DATA\r\n") - 1));
+ CHKiRet(readResponse(pData, &iState, 354));
+
+ /* now come the data part */
+ /* header */
+ mkSMTPTimestamp(szDateBuf, sizeof(szDateBuf));
+ CHKiRet(Send(pData->md.smtp.sock, (char*)szDateBuf, strlen((char*)szDateBuf)));
+
+ CHKiRet(Send(pData->md.smtp.sock, "From: <", sizeof("From: <") - 1));
+ CHKiRet(Send(pData->md.smtp.sock, (char*)pData->md.smtp.pszFrom, strlen((char*)pData->md.smtp.pszFrom)));
+ CHKiRet(Send(pData->md.smtp.sock, ">\r\n", sizeof(">\r\n") - 1));
+
+ CHKiRet(Send(pData->md.smtp.sock, "To: <", sizeof("To: <") - 1));
+ CHKiRet(Send(pData->md.smtp.sock, (char*)pData->md.smtp.pszTo, strlen((char*)pData->md.smtp.pszTo)));
+ CHKiRet(Send(pData->md.smtp.sock, ">\r\n", sizeof(">\r\n") - 1));
+
+ CHKiRet(Send(pData->md.smtp.sock, "Subject: ", sizeof("Subject: ") - 1));
+ CHKiRet(Send(pData->md.smtp.sock, (char*)subject, strlen((char*)subject)));
+ CHKiRet(Send(pData->md.smtp.sock, "\r\n", sizeof("\r\n") - 1));
+
+ CHKiRet(Send(pData->md.smtp.sock, "X-Mailer: rsyslog-immail\r\n", sizeof("x-mailer: rsyslog-immail\r\n") - 1));
+
+ CHKiRet(Send(pData->md.smtp.sock, "\r\n", sizeof("\r\n") - 1)); /* indicate end of header */
+
+ /* body */
+ if(pData->bEnableBody)
+ CHKiRet(bodySend(pData, (char*)body, strlen((char*) body)));
+
+ /* end of data, back to envelope transaction */
+ CHKiRet(Send(pData->md.smtp.sock, "\r\n.\r\n", sizeof("\r\n.\r\n") - 1));
+ CHKiRet(readResponse(pData, &iState, 250));
+
+ CHKiRet(Send(pData->md.smtp.sock, "QUIT\r\n", sizeof("QUIT\r\n") - 1));
+ CHKiRet(readResponse(pData, &iState, 221));
+
+ /* we are finished, a new connection is created for each request, so let's close it now */
+ CHKiRet(serverDisconnect(pData));
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* in tryResume we check if we can connect to the server in question. If that is OK,
+ * we close the connection without doing any actual SMTP transaction. It will be
+ * reopened during the actual send process. This may not be the best way to do it if
+ * there is a problem inside the SMTP transaction. However, we can't find that out without
+ * actually initiating something, and that would be bad. The logic here helps us
+ * correctly recover from an unreachable/down mail server, which is probably the majority
+ * of problem cases. For SMTP transaction problems, we will do lots of retries, but if it
+ * is a temporary problem, it will be fixed anyhow. So I consider this implementation to
+ * be clean enough, especially as I think other approaches have other weaknesses.
+ * rgerhards, 2008-04-08
+ */
+BEGINtryResume
+CODESTARTtryResume
+ CHKiRet(serverConnect(pData));
+ CHKiRet(serverDisconnect(pData)); /* if we fail, we will never reach this line */
+finalize_it:
+ if(iRet == RS_RET_IO_ERROR)
+ iRet = RS_RET_SUSPENDED;
+ENDtryResume
+
+
+BEGINdoAction
+CODESTARTdoAction
+ dbgprintf(" Mail\n");
+
+ /* forward */
+ if(pData->bHaveSubject)
+ iRet = sendSMTP(pData, ppString[0], ppString[1]);
+ else
+ iRet = sendSMTP(pData, ppString[0], (uchar*)"message from rsyslog");
+
+ if(iRet != RS_RET_OK) {
+ /* error! */
+ dbgprintf("error sending mail, suspending\n");
+ iRet = RS_RET_SUSPENDED;
+ }
+ENDdoAction
+
+
+BEGINparseSelectorAct
+CODESTARTparseSelectorAct
+ if(!strncmp((char*) p, ":ommail:", sizeof(":ommail:") - 1)) {
+ p += sizeof(":ommail:") - 1; /* eat indicator sequence (-1 because of '\0'!) */
+ } else {
+ ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED);
+ }
+
+ /* ok, if we reach this point, we have something for us */
+ if((iRet = createInstance(&pData)) != RS_RET_OK)
+ FINALIZE;
+
+ /* TODO: check strdup() result */
+
+ if(pszFrom == NULL) {
+ errmsg.LogError(NO_ERRCODE, "no sender address given - specify $ActionMailFrom");
+ ABORT_FINALIZE(RS_RET_MAIL_NO_FROM);
+ }
+ if(pszTo == NULL) {
+ errmsg.LogError(NO_ERRCODE, "no recipient address given - specify $ActionMailTo");
+ ABORT_FINALIZE(RS_RET_MAIL_NO_TO);
+ }
+
+ pData->md.smtp.pszFrom = (uchar*) strdup((char*)pszFrom);
+ pData->md.smtp.pszTo = (uchar*) strdup((char*)pszTo);
+
+ if(pszSubject == NULL) {
+ /* if no subject is configured, we need just one template string */
+ CODE_STD_STRING_REQUESTparseSelectorAct(1)
+ } else {
+ CODE_STD_STRING_REQUESTparseSelectorAct(2)
+ pData->bHaveSubject = 1;
+ CHKiRet(OMSRsetEntry(*ppOMSR, 1, (uchar*)strdup((char*) pszSubject), OMSR_NO_RQD_TPL_OPTS));
+ }
+ if(pszSrv != NULL)
+ pData->md.smtp.pszSrv = (uchar*) strdup((char*)pszSrv);
+ if(pszSrvPort != NULL)
+ pData->md.smtp.pszSrvPort = (uchar*) strdup((char*)pszSrvPort);
+ pData->bEnableBody = bEnableBody;
+
+ /* process template */
+ CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, (uchar*) "RSYSLOG_FileFormat"));
+CODE_STD_FINALIZERparseSelectorAct
+ENDparseSelectorAct
+
+
+/* Free string config variables and reset them to NULL (not necessarily the default!) */
+static rsRetVal freeConfigVariables(void)
+{
+ DEFiRet;
+
+ if(pszSrv != NULL) {
+ free(pszSrv);
+ pszSrv = NULL;
+ }
+ if(pszSrvPort != NULL) {
+ free(pszSrvPort);
+ pszSrvPort = NULL;
+ }
+ if(pszFrom != NULL) {
+ free(pszFrom);
+ pszFrom = NULL;
+ }
+ if(pszTo != NULL) {
+ free(pszTo);
+ pszTo = NULL;
+ }
+
+ RETiRet;
+}
+
+
+BEGINmodExit
+CODESTARTmodExit
+ /* cleanup our allocations */
+ freeConfigVariables();
+
+ /* release what we no longer need */
+ objRelease(errmsg, CORE_COMPONENT);
+ENDmodExit
+
+
+BEGINqueryEtryPt
+CODESTARTqueryEtryPt
+CODEqueryEtryPt_STD_OMOD_QUERIES
+ENDqueryEtryPt
+
+
+/* Reset config variables for this module to default values.
+ */
+static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
+{
+ DEFiRet;
+ bEnableBody = 1;
+ iRet = freeConfigVariables();
+ RETiRet;
+}
+
+
+BEGINmodInit()
+CODESTARTmodInit
+ *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
+CODEmodInit_QueryRegCFSLineHdlr
+ /* tell which objects we need */
+ CHKiRet(objUse(errmsg, CORE_COMPONENT));
+
+ CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionmailsmtpserver", 0, eCmdHdlrGetWord, NULL, &pszSrv, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionmailsmtpport", 0, eCmdHdlrGetWord, NULL, &pszSrvPort, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionmailfrom", 0, eCmdHdlrGetWord, NULL, &pszFrom, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionmailto", 0, eCmdHdlrGetWord, NULL, &pszTo, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionmailsubject", 0, eCmdHdlrGetWord, NULL, &pszSubject, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionmailenablebody", 0, eCmdHdlrBinary, NULL, &bEnableBody, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr( (uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
+ENDmodInit
+
+/* vim:set ai:
+ */
diff --git a/plugins/omrelp/omrelp.c b/plugins/omrelp/omrelp.c
index 39d25812..04571682 100644
--- a/plugins/omrelp/omrelp.c
+++ b/plugins/omrelp/omrelp.c
@@ -53,7 +53,7 @@ DEFobjCurrIf(errmsg)
static relpEngine_t *pRelpEngine; /* our relp engine */
typedef struct _instanceData {
- char f_hname[MAXHOSTNAMELEN+1];
+ char *f_hname;
int compressionLevel; /* 0 - no compression, else level for zlib */
char *port;
int bInitialConnect; /* is this the initial connection request of our module? (0-no, 1-yes) */
@@ -98,6 +98,9 @@ CODESTARTfreeInstance
if(pData->pRelpClt != NULL)
relpEngineCltDestruct(pRelpEngine, &pData->pRelpClt);
+ if(pData->f_hname != NULL)
+ free(pData->f_hname);
+
ENDfreeInstance
@@ -284,10 +287,11 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1)
/* TODO: make this if go away! */
if(*p == ';') {
*p = '\0'; /* trick to obtain hostname (later)! */
- strcpy(pData->f_hname, (char*) q);
+ CHKmalloc(pData->f_hname = strdup((char*) q));
*p = ';';
- } else
- strcpy(pData->f_hname, (char*) q);
+ } else {
+ CHKmalloc(pData->f_hname = strdup((char*) q));
+ }
/* process template */
CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, (uchar*) "RSYSLOG_ForwardFormat"));