summaryrefslogtreecommitdiffstats
path: root/plugins/imuxsock/imuxsock.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--plugins/imuxsock/imuxsock.c1767
1 files changed, 1767 insertions, 0 deletions
diff --git a/plugins/imuxsock/imuxsock.c b/plugins/imuxsock/imuxsock.c
new file mode 100644
index 0000000..1ae550e
--- /dev/null
+++ b/plugins/imuxsock/imuxsock.c
@@ -0,0 +1,1767 @@
+/* imuxsock.c
+ * This is the implementation of the Unix sockets input module.
+ *
+ * NOTE: read comments in module-template.h to understand how this file
+ * works!
+ *
+ * File begun on 2007-12-20 by RGerhards (extracted from syslogd.c)
+ *
+ * Copyright 2007-2019 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.
+ */
+#ifdef __sun
+#define _XPG4_2
+#endif
+#include "config.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <assert.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <sys/socket.h>
+#ifdef HAVE_LIBSYSTEMD
+# include <systemd/sd-daemon.h>
+#endif
+#if defined(__FreeBSD__)
+ #include <sys/param.h>
+#endif
+#include "rsyslog.h"
+#include "dirty.h"
+#include "cfsysline.h"
+#include "unicode-helper.h"
+#include "module-template.h"
+#include "srUtils.h"
+#include "errmsg.h"
+#include "net.h"
+#include "glbl.h"
+#include "msg.h"
+#include "parser.h"
+#include "prop.h"
+#include "debug.h"
+#include "ruleset.h"
+#include "unlimited_select.h"
+#include "statsobj.h"
+#include "datetime.h"
+#include "hashtable.h"
+#include "ratelimit.h"
+
+
+MODULE_TYPE_INPUT
+MODULE_TYPE_NOKEEP
+MODULE_CNFNAME("imuxsock")
+
+/* defines */
+#ifndef _PATH_LOG
+#ifdef BSD
+#define _PATH_LOG "/var/run/log"
+#else
+#define _PATH_LOG "/dev/log"
+#endif
+#endif
+#ifndef SYSTEMD_JOURNAL
+#define SYSTEMD_JOURNAL "/run/systemd/journal"
+#endif
+#ifndef SYSTEMD_PATH_LOG
+#define SYSTEMD_PATH_LOG SYSTEMD_JOURNAL "/syslog"
+#endif
+#define UNSET -1 /* to indicate a value has not been configured */
+
+/* forward definitions */
+static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal);
+
+#if defined(_AIX)
+#define ucred ucred_t
+#endif
+/* emulate struct ucred for platforms that do not have it */
+#ifndef HAVE_SCM_CREDENTIALS
+struct ucred { int pid; uid_t uid; gid_t gid; };
+#endif
+
+/* handle some defines missing on more than one platform */
+#ifndef SUN_LEN
+#define SUN_LEN(su) \
+ (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
+#endif
+/* Module static data */
+DEF_IMOD_STATIC_DATA
+DEFobjCurrIf(glbl)
+DEFobjCurrIf(prop)
+DEFobjCurrIf(net)
+DEFobjCurrIf(parser)
+DEFobjCurrIf(datetime)
+DEFobjCurrIf(statsobj)
+DEFobjCurrIf(ruleset)
+
+
+statsobj_t *modStats;
+STATSCOUNTER_DEF(ctrSubmit, mutCtrSubmit)
+STATSCOUNTER_DEF(ctrLostRatelimit, mutCtrLostRatelimit)
+STATSCOUNTER_DEF(ctrNumRatelimiters, mutCtrNumRatelimiters)
+
+
+/* a very simple "hash function" for process IDs - we simply use the
+ * pid itself: it is quite expected that all pids may log some time, but
+ * from a collision point of view it is likely that long-running daemons
+ * start early and so will stay right in the top spots of the
+ * collision list.
+ */
+static unsigned int
+hash_from_key_fn(void *k)
+{
+ return((unsigned) *((pid_t*) k));
+}
+
+static int
+key_equals_fn(void *key1, void *key2)
+{
+ return *((pid_t*) key1) == *((pid_t*) key2);
+}
+
+
+/* structure to describe a specific listener */
+typedef struct lstn_s {
+ uchar *sockName; /* read-only after startup */
+ prop_t *hostName; /* host-name override - if set, use this instead of actual name */
+ int fd; /* read-only after startup */
+ int flags; /* should parser parse host name? read-only after startup */
+ int flowCtl; /* flow control settings for this socket */
+ unsigned int ratelimitInterval;
+ unsigned int ratelimitBurst;
+ ratelimit_t *dflt_ratelimiter;/*ratelimiter to apply if none else is to be used */
+ intTiny ratelimitSev; /* severity level (and below) for which rate-limiting shall apply */
+ struct hashtable *ht; /* our hashtable for rate-limiting */
+ sbool bParseHost; /* should parser parse host name? read-only after startup */
+ sbool bCreatePath; /* auto-creation of socket directory? */
+ sbool bUseCreds; /* pull original creator credentials from socket */
+ sbool bAnnotate; /* annotate events with trusted properties */
+ sbool bParseTrusted; /* parse trusted properties */
+ sbool bWritePid; /* write original PID into tag */
+ sbool bDiscardOwnMsgs; /* discard messages that originated from ourselves */
+ sbool bUseSysTimeStamp; /* use timestamp from system (instead of from message) */
+ sbool bUnlink; /* unlink&re-create socket at start and end of processing */
+ sbool bUseSpecialParser;/* use "canned" log socket parser instead of parser chain? */
+ ruleset_t *pRuleset;
+} lstn_t;
+static lstn_t *listeners;
+
+static prop_t *pLocalHostIP = NULL; /* there is only one global IP for all internally-generated messages */
+static prop_t *pInputName = NULL; /* our inputName currently is always "imuxsock", and this will hold it */
+static int startIndexUxLocalSockets; /* process fd from that index on (used to
+ * suppress local logging. rgerhards 2005-08-01
+ * read-only after startup
+ */
+static int nfd = 1; /* number of active unix sockets (socket 0 is always reserved for the system
+ socket, even if it is not enabled. */
+static int sd_fds = 0; /* number of systemd activated sockets */
+
+#if (defined(__FreeBSD__) && (__FreeBSD_version >= 1200061))
+ #define DFLT_bUseSpecialParser 0
+#else
+ #define DFLT_bUseSpecialParser 1
+#endif
+#define DFLT_bCreatePath 0
+#define DFLT_ratelimitInterval 0
+#define DFLT_ratelimitBurst 200
+#define DFLT_ratelimitSeverity 1 /* do not rate-limit emergency messages */
+/* config vars for the legacy config system */
+static struct configSettings_s {
+ int bOmitLocalLogging;
+ uchar *pLogSockName;
+ uchar *pLogHostName; /* host name to use with this socket */
+ int bUseFlowCtl; /* use flow control or not (if yes, only LIGHT is used!) */
+ int bUseFlowCtlSysSock;
+ int bIgnoreTimestamp; /* ignore timestamps present in the incoming message? */
+ int bIgnoreTimestampSysSock;
+ int bUseSysTimeStamp; /* use timestamp from system (rather than from message) */
+ int bUseSysTimeStampSysSock; /* same, for system log socket */
+ int bWritePid; /* use credentials from recvmsg() and fixup PID in TAG */
+ int bWritePidSysSock; /* use credentials from recvmsg() and fixup PID in TAG */
+ int bCreatePath; /* auto-create socket path? */
+ unsigned int ratelimitInterval; /* interval in seconds, 0 = off */
+ unsigned int ratelimitIntervalSysSock;
+ unsigned int ratelimitBurst; /* max nbr of messages in interval */
+ unsigned int ratelimitBurstSysSock;
+ int ratelimitSeverity;
+ int ratelimitSeveritySysSock;
+ int bAnnotate; /* annotate trusted properties */
+ int bAnnotateSysSock; /* same, for system log socket */
+ int bParseTrusted; /* parse trusted properties */
+} cs;
+
+/* config vars for the v2 config system (rsyslog v6+) */
+struct instanceConf_s {
+ uchar *sockName;
+ uchar *pLogHostName; /* host name to use with this socket */
+ sbool bUseFlowCtl; /* use flow control or not (if yes, only LIGHT is used! */
+ sbool bIgnoreTimestamp; /* ignore timestamps present in the incoming message? */
+ sbool bWritePid; /* use credentials from recvmsg() and fixup PID in TAG */
+ sbool bUseSysTimeStamp; /* use timestamp from system (instead of from message) */
+ int bCreatePath; /* auto-create socket path? */
+ unsigned int ratelimitInterval; /* interval in seconds, 0 = off */
+ unsigned int ratelimitBurst; /* max nbr of messages in interval */
+ int ratelimitSeverity;
+ int bAnnotate; /* annotate trusted properties */
+ int bParseTrusted; /* parse trusted properties */
+ sbool bDiscardOwnMsgs; /* discard messages that originated from our own pid? */
+ sbool bUnlink;
+ sbool bUseSpecialParser;
+ sbool bParseHost;
+ uchar *pszBindRuleset; /* name of ruleset to bind to */
+ ruleset_t *pBindRuleset; /* ruleset to bind listener to (use system default if unspecified) */
+ struct instanceConf_s *next;
+};
+
+struct modConfData_s {
+ rsconf_t *pConf; /* our overall config object */
+ instanceConf_t *root, *tail;
+ uchar *pLogSockName;
+ unsigned int ratelimitIntervalSysSock;
+ unsigned int ratelimitBurstSysSock;
+ int ratelimitSeveritySysSock;
+ int bAnnotateSysSock;
+ int bParseTrusted;
+ int bUseSpecialParser;
+ int bParseHost;
+ sbool bIgnoreTimestamp; /* ignore timestamps present in the incoming message? */
+ sbool bUseFlowCtl; /* use flow control or not (if yes, only LIGHT is used! */
+ sbool bOmitLocalLogging;
+ sbool bWritePidSysSock;
+ sbool bUseSysTimeStamp;
+ sbool bDiscardOwnMsgs;
+ sbool configSetViaV2Method;
+ sbool bUnlink;
+};
+static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */
+static modConfData_t *runModConf = NULL;/* modConf ptr to use for the current load process */
+
+/* module-global parameters */
+static struct cnfparamdescr modpdescr[] = {
+ { "syssock.use", eCmdHdlrBinary, 0 },
+ { "syssock.name", eCmdHdlrGetWord, 0 },
+ { "syssock.unlink", eCmdHdlrBinary, 0 },
+ { "syssock.ignoretimestamp", eCmdHdlrBinary, 0 },
+ { "syssock.ignoreownmessages", eCmdHdlrBinary, 0 },
+ { "syssock.flowcontrol", eCmdHdlrBinary, 0 },
+ { "syssock.usesystimestamp", eCmdHdlrBinary, 0 },
+ { "syssock.annotate", eCmdHdlrBinary, 0 },
+ { "syssock.parsetrusted", eCmdHdlrBinary, 0 },
+ { "syssock.usespecialparser", eCmdHdlrBinary, 0 },
+ { "syssock.parsehostname", eCmdHdlrBinary, 0 },
+ { "syssock.usepidfromsystem", eCmdHdlrBinary, 0 },
+ { "syssock.ratelimit.interval", eCmdHdlrInt, 0 },
+ { "syssock.ratelimit.burst", eCmdHdlrInt, 0 },
+ { "syssock.ratelimit.severity", eCmdHdlrInt, 0 }
+};
+static struct cnfparamblk modpblk =
+ { CNFPARAMBLK_VERSION,
+ sizeof(modpdescr)/sizeof(struct cnfparamdescr),
+ modpdescr
+ };
+
+/* input instance parameters */
+static struct cnfparamdescr inppdescr[] = {
+ { "socket", eCmdHdlrString, CNFPARAM_REQUIRED }, /* legacy: addunixlistensocket */
+ { "unlink", eCmdHdlrBinary, 0 },
+ { "createpath", eCmdHdlrBinary, 0 },
+ { "parsetrusted", eCmdHdlrBinary, 0 },
+ { "ignoreownmessages", eCmdHdlrBinary, 0 },
+ { "hostname", eCmdHdlrString, 0 },
+ { "ignoretimestamp", eCmdHdlrBinary, 0 },
+ { "flowcontrol", eCmdHdlrBinary, 0 },
+ { "usesystimestamp", eCmdHdlrBinary, 0 },
+ { "annotate", eCmdHdlrBinary, 0 },
+ { "usespecialparser", eCmdHdlrBinary, 0 },
+ { "parsehostname", eCmdHdlrBinary, 0 },
+ { "usepidfromsystem", eCmdHdlrBinary, 0 },
+ { "ruleset", eCmdHdlrString, 0 },
+ { "ratelimit.interval", eCmdHdlrInt, 0 },
+ { "ratelimit.burst", eCmdHdlrInt, 0 },
+ { "ratelimit.severity", eCmdHdlrInt, 0 }
+};
+static struct cnfparamblk inppblk =
+ { CNFPARAMBLK_VERSION,
+ sizeof(inppdescr)/sizeof(struct cnfparamdescr),
+ inppdescr
+ };
+
+#include "im-helper.h" /* must be included AFTER the type definitions! */
+
+static int bLegacyCnfModGlobalsPermitted;/* are legacy module-global config parameters permitted? */
+
+
+/* create input instance, set default parameters, and
+ * add it to the list of instances.
+ */
+static rsRetVal
+createInstance(instanceConf_t **pinst)
+{
+ instanceConf_t *inst;
+ DEFiRet;
+ CHKmalloc(inst = malloc(sizeof(instanceConf_t)));
+ inst->sockName = NULL;
+ inst->pLogHostName = NULL;
+ inst->pszBindRuleset = NULL;
+ inst->pBindRuleset = NULL;
+ inst->ratelimitInterval = DFLT_ratelimitInterval;
+ inst->ratelimitBurst = DFLT_ratelimitBurst;
+ inst->ratelimitSeverity = DFLT_ratelimitSeverity;
+ inst->bUseFlowCtl = 0;
+ inst->bUseSpecialParser = DFLT_bUseSpecialParser;
+ inst->bParseHost = UNSET;
+ inst->bIgnoreTimestamp = 1;
+ inst->bCreatePath = DFLT_bCreatePath;
+ inst->bUseSysTimeStamp = 1;
+ inst->bWritePid = 0;
+ inst->bAnnotate = 0;
+ inst->bParseTrusted = 0;
+ inst->bDiscardOwnMsgs = loadModConf->pConf->globals.bProcessInternalMessages;
+ inst->bUnlink = 1;
+ inst->next = NULL;
+
+ /* node created, let's add to config */
+ if(loadModConf->tail == NULL) {
+ loadModConf->tail = loadModConf->root = inst;
+ } else {
+ loadModConf->tail->next = inst;
+ loadModConf->tail = inst;
+ }
+
+ *pinst = inst;
+finalize_it:
+ RETiRet;
+}
+
+
+/* This function is called when a new listen socket instance shall be added to
+ * the current config object via the legacy config system. It just shuffles
+ * all parameters to the listener in-memory instance.
+ * rgerhards, 2011-05-12
+ */
+static rsRetVal addInstance(void __attribute__((unused)) *pVal, uchar *pNewVal)
+{
+ instanceConf_t *inst;
+ DEFiRet;
+
+ if(pNewVal == NULL || pNewVal[0] == '\0') {
+ LogError(0, RS_RET_SOCKNAME_MISSING , "imuxsock: socket name must be specified, "
+ "but is not - listener not created\n");
+ if(pNewVal != NULL)
+ free(pNewVal);
+ ABORT_FINALIZE(RS_RET_SOCKNAME_MISSING);
+ }
+
+ CHKiRet(createInstance(&inst));
+ inst->sockName = pNewVal;
+ inst->ratelimitInterval = cs.ratelimitInterval;
+ inst->pLogHostName = cs.pLogHostName;
+ inst->ratelimitBurst = cs.ratelimitBurst;
+ inst->ratelimitSeverity = cs.ratelimitSeverity;
+ inst->bUseFlowCtl = cs.bUseFlowCtl;
+ inst->bIgnoreTimestamp = cs.bIgnoreTimestamp;
+ inst->bCreatePath = cs.bCreatePath;
+ inst->bUseSysTimeStamp = cs.bUseSysTimeStamp;
+ inst->bWritePid = cs.bWritePid;
+ inst->bAnnotate = cs.bAnnotate;
+ inst->bParseTrusted = cs.bParseTrusted;
+ inst->bParseHost = UNSET;
+ inst->next = NULL;
+
+ /* reset hostname for next socket */
+ cs.pLogHostName = NULL;
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* add an additional listen socket.
+ * added capability to specify hostname for socket -- rgerhards, 2008-08-01
+ */
+static rsRetVal
+addListner(instanceConf_t *inst)
+{
+ DEFiRet;
+
+ if(inst->bParseHost == UNSET) {
+ if(*inst->sockName == ':') {
+ listeners[nfd].bParseHost = 1;
+ } else {
+ listeners[nfd].bParseHost = 0;
+ }
+ } else {
+ listeners[nfd].bParseHost = inst->bParseHost;
+ }
+ if(inst->pLogHostName == NULL) {
+ listeners[nfd].hostName = NULL;
+ } else {
+ CHKiRet(prop.Construct(&(listeners[nfd].hostName)));
+ CHKiRet(prop.SetString(listeners[nfd].hostName, inst->pLogHostName, ustrlen(inst->pLogHostName)));
+ CHKiRet(prop.ConstructFinalize(listeners[nfd].hostName));
+ }
+ if(inst->ratelimitInterval > 0) {
+ if((listeners[nfd].ht = create_hashtable(100, hash_from_key_fn, key_equals_fn,
+ (void(*)(void*))ratelimitDestruct)) == NULL) {
+ /* in this case, we simply turn off rate-limiting */
+ DBGPRINTF("imuxsock: turning off rate limiting because we could not "
+ "create hash table\n");
+ inst->ratelimitInterval = 0;
+ }
+ } else {
+ listeners[nfd].ht = NULL;
+ }
+ listeners[nfd].ratelimitInterval = inst->ratelimitInterval;
+ listeners[nfd].ratelimitBurst = inst->ratelimitBurst;
+ listeners[nfd].ratelimitSev = inst->ratelimitSeverity;
+ listeners[nfd].flowCtl = inst->bUseFlowCtl ? eFLOWCTL_LIGHT_DELAY : eFLOWCTL_NO_DELAY;
+ listeners[nfd].flags = inst->bIgnoreTimestamp ? IGNDATE : NOFLAG;
+ listeners[nfd].bCreatePath = inst->bCreatePath;
+ listeners[nfd].sockName = ustrdup(inst->sockName);
+ listeners[nfd].bUseCreds = (inst->bDiscardOwnMsgs || inst->bWritePid || inst->ratelimitInterval
+ || inst->bAnnotate || inst->bUseSysTimeStamp) ? 1 : 0;
+ listeners[nfd].bAnnotate = inst->bAnnotate;
+ listeners[nfd].bParseTrusted = inst->bParseTrusted;
+ listeners[nfd].bDiscardOwnMsgs = inst->bDiscardOwnMsgs;
+ listeners[nfd].bUnlink = inst->bUnlink;
+ listeners[nfd].bWritePid = inst->bWritePid;
+ listeners[nfd].bUseSysTimeStamp = inst->bUseSysTimeStamp;
+ listeners[nfd].bUseSpecialParser = inst->bUseSpecialParser;
+ listeners[nfd].pRuleset = inst->pBindRuleset;
+ CHKiRet(ratelimitNew(&listeners[nfd].dflt_ratelimiter, "imuxsock", NULL));
+ ratelimitSetLinuxLike(listeners[nfd].dflt_ratelimiter,
+ listeners[nfd].ratelimitInterval,
+ listeners[nfd].ratelimitBurst);
+ ratelimitSetSeverity(listeners[nfd].dflt_ratelimiter,
+ listeners[nfd].ratelimitSev);
+ nfd++;
+
+finalize_it:
+ RETiRet;
+}
+
+
+static rsRetVal discardLogSockets(void)
+{
+ int i;
+
+ /* Check whether the system socket is in use */
+ if(startIndexUxLocalSockets == 0) {
+ /* Clean up rate limiting data for the system socket */
+ if(listeners[0].ht != NULL) {
+ hashtable_destroy(listeners[0].ht, 1); /* 1 => free all values automatically */
+ }
+ ratelimitDestruct(listeners[0].dflt_ratelimiter);
+ }
+
+ /* Clean up all other sockets */
+ for (i = 1; i < nfd; i++) {
+ if(listeners[i].sockName != NULL) {
+ free(listeners[i].sockName);
+ listeners[i].sockName = NULL;
+ }
+ if(listeners[i].hostName != NULL) {
+ prop.Destruct(&(listeners[i].hostName));
+ }
+ if(listeners[i].ht != NULL) {
+ hashtable_destroy(listeners[i].ht, 1); /* 1 => free all values automatically */
+ }
+ ratelimitDestruct(listeners[i].dflt_ratelimiter);
+ }
+
+ return RS_RET_OK;
+}
+
+
+/* used to create a log socket if NOT passed in via systemd.
+ */
+/* note: the linux SUN_LEN macro uses a sizeof based on a NULL pointer. This
+ * triggers UBSan warning. As such, we turn that warning off for the fuction.
+ * As it is OS-provided, there is no way to solve it ourselves. The problem
+ * may also exist on other platforms, we have just noticed it on Linux.
+ */
+#if defined(__clang__)
+#pragma GCC diagnostic ignored "-Wunknown-attributes"
+#endif
+static rsRetVal
+#if defined(__clang__)
+__attribute__((no_sanitize("undefined")))
+#endif
+createLogSocket(lstn_t *pLstn)
+{
+ struct sockaddr_un sunx;
+ DEFiRet;
+
+ if(pLstn->bUnlink)
+ unlink((char*)pLstn->sockName);
+ memset(&sunx, 0, sizeof(sunx));
+ sunx.sun_family = AF_UNIX;
+ if(pLstn->bCreatePath) {
+ makeFileParentDirs((uchar*)pLstn->sockName, ustrlen(pLstn->sockName), 0755, -1, -1, 0);
+ }
+ strncpy(sunx.sun_path, (char*)pLstn->sockName, sizeof(sunx.sun_path));
+ sunx.sun_path[sizeof(sunx.sun_path)-1] = '\0';
+ pLstn->fd = socket(AF_UNIX, SOCK_DGRAM, 0);
+ if(pLstn->fd < 0 ) {
+ ABORT_FINALIZE(RS_RET_ERR_CRE_AFUX);
+ }
+ if(bind(pLstn->fd, (struct sockaddr *) &sunx, SUN_LEN(&sunx)) < 0) {
+ ABORT_FINALIZE(RS_RET_ERR_CRE_AFUX);
+ }
+ if(chmod((char*)pLstn->sockName, 0666) < 0) {
+ ABORT_FINALIZE(RS_RET_ERR_CRE_AFUX);
+ }
+finalize_it:
+ if(iRet != RS_RET_OK) {
+ LogError(errno, iRet, "cannot create '%s'", pLstn->sockName);
+ if(pLstn->fd != -1) {
+ close(pLstn->fd);
+ pLstn->fd = -1;
+ }
+ }
+ RETiRet;
+}
+
+
+static rsRetVal
+openLogSocket(lstn_t *pLstn)
+{
+ DEFiRet;
+# ifdef HAVE_SCM_CREDENTIALS
+ int one;
+# endif /* HAVE_SCM_CREDENTIALS */
+
+ if(pLstn->sockName[0] == '\0')
+ return -1;
+
+ pLstn->fd = -1;
+
+#ifdef HAVE_LIBSYSTEMD
+ if (sd_fds > 0) {
+ /* Check if the current socket is a systemd activated one.
+ * If so, just use it.
+ */
+ int fd;
+
+ for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + sd_fds; fd++) {
+ if( sd_is_socket_unix(fd, SOCK_DGRAM, -1, (const char*) pLstn->sockName, 0) == 1) {
+ /* ok, it matches -- just use as is */
+ pLstn->fd = fd;
+
+ LogMsg(0, NO_ERRCODE, LOG_INFO,
+ "imuxsock: Acquired UNIX socket '%s' (fd %d) from systemd.\n",
+ pLstn->sockName, pLstn->fd);
+ break;
+ }
+ /*
+ * otherwise it either didn't match *this* socket and
+ * we just continue to check the next one or there was
+ * an error and we will create a new socket below.
+ */
+ }
+ }
+#endif
+
+ if (pLstn->fd == -1) {
+ CHKiRet(createLogSocket(pLstn));
+ assert(pLstn->fd != -1); /* else createLogSocket() should have failed! */
+ }
+
+# ifdef HAVE_SCM_CREDENTIALS
+ if(pLstn->bUseCreds) {
+ one = 1;
+ if(setsockopt(pLstn->fd, SOL_SOCKET, SO_PASSCRED, &one, (socklen_t) sizeof(one)) != 0) {
+ LogError(errno, NO_ERRCODE, "set SO_PASSCRED failed on '%s'", pLstn->sockName);
+ pLstn->bUseCreds = 0;
+ }
+// TODO: move to its own #if
+ if(setsockopt(pLstn->fd, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one)) != 0) {
+ LogError(errno, NO_ERRCODE, "set SO_TIMESTAMP failed on '%s'", pLstn->sockName);
+ }
+ }
+# else /* HAVE_SCM_CREDENTIALS */
+ pLstn->bUseCreds = 0;
+ pLstn->bAnnotate = 0;
+# endif /* HAVE_SCM_CREDENTIALS */
+
+finalize_it:
+ if(iRet != RS_RET_OK) {
+ if(pLstn->fd != -1) {
+ close(pLstn->fd);
+ pLstn->fd = -1;
+ }
+ }
+
+ RETiRet;
+}
+
+
+/* find ratelimiter to use for this message. Currently, we use the
+ * pid, but may change to cgroup later (probably via a config switch).
+ * Returns NULL if not found or rate-limiting not activated for this
+ * listener (the latter being a performance enhancement).
+ */
+static rsRetVal
+findRatelimiter(lstn_t *pLstn, struct ucred *cred, ratelimit_t **prl)
+{
+ ratelimit_t *rl = NULL;
+ int r;
+ pid_t *keybuf;
+ char pinfobuf[512];
+ DEFiRet;
+
+ if(cred == NULL)
+ FINALIZE;
+#if 0 // TODO: check deactivated?
+ if(pLstn->ratelimitInterval == 0) {
+ *prl = NULL;
+ FINALIZE;
+ }
+#endif
+ if(pLstn->ht == NULL) {
+ *prl = NULL;
+ FINALIZE;
+ }
+
+ rl = hashtable_search(pLstn->ht, &cred->pid);
+ if(rl == NULL) {
+ /* we need to add a new ratelimiter, process not seen before! */
+ DBGPRINTF("imuxsock: no ratelimiter for pid %lu, creating one\n",
+ (unsigned long) cred->pid);
+ STATSCOUNTER_INC(ctrNumRatelimiters, mutCtrNumRatelimiters);
+ /* read process name from system */
+ char procName[256]; /* enough for any sane process name */
+ snprintf(procName, sizeof(procName), "/proc/%lu/cmdline", (unsigned long) cred->pid);
+ FILE *f = fopen(procName, "r");
+ if (f) {
+ size_t len;
+ len = fread(procName, sizeof(char), 256, f);
+ if (len > 0) {
+ snprintf(pinfobuf, sizeof(pinfobuf), "pid: %lu, name: %s",
+ (unsigned long) cred->pid, procName);
+ }
+ fclose(f);
+ }
+ else {
+ snprintf(pinfobuf, sizeof(pinfobuf), "pid: %lu",
+ (unsigned long) cred->pid);
+ }
+ pinfobuf[sizeof(pinfobuf)-1] = '\0'; /* to be on safe side */
+ CHKiRet(ratelimitNew(&rl, "imuxsock", pinfobuf));
+ ratelimitSetLinuxLike(rl, pLstn->ratelimitInterval, pLstn->ratelimitBurst);
+ ratelimitSetSeverity(rl, pLstn->ratelimitSev);
+ CHKmalloc(keybuf = malloc(sizeof(pid_t)));
+ *keybuf = cred->pid;
+ r = hashtable_insert(pLstn->ht, keybuf, rl);
+ if(r == 0)
+ ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
+ }
+
+ *prl = rl;
+ rl = NULL;
+
+finalize_it:
+ if(rl != NULL)
+ ratelimitDestruct(rl);
+ if(*prl == NULL)
+ *prl = pLstn->dflt_ratelimiter;
+ RETiRet;
+}
+
+
+/* patch correct pid into tag. bufTAG MUST be CONF_TAG_MAXSIZE long!
+ */
+static void
+fixPID(uchar *bufTAG, int *lenTag, struct ucred *cred)
+{
+ int i;
+ char bufPID[16];
+ int lenPID;
+
+ if(cred == NULL)
+ return;
+
+ lenPID = snprintf(bufPID, sizeof(bufPID), "[%lu]:", (unsigned long) cred->pid);
+
+ for(i = *lenTag ; i >= 0 && bufTAG[i] != '[' ; --i)
+ /*JUST SKIP*/;
+
+ if(i < 0)
+ i = *lenTag - 1; /* go right at end of TAG, pid was not present (-1 for ':') */
+
+ if(i + lenPID > CONF_TAG_MAXSIZE)
+ return; /* do not touch, as things would break */
+
+ memcpy(bufTAG + i, bufPID, lenPID);
+ *lenTag = i + lenPID;
+}
+
+
+/* Get an "trusted property" from the system. Returns an empty string if the
+ * property can not be obtained. Inspired by similiar functionality inside
+ * journald. Currently works with Linux /proc filesystem, only.
+ */
+static rsRetVal
+getTrustedProp(struct ucred *cred, const char *propName, uchar *buf, size_t lenBuf, int *lenProp)
+{
+ int fd;
+ int i;
+ int lenRead;
+ char namebuf[1024];
+ DEFiRet;
+
+ if(snprintf(namebuf, sizeof(namebuf), "/proc/%lu/%s", (long unsigned) cred->pid,
+ propName) >= (int) sizeof(namebuf)) {
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+
+ if((fd = open(namebuf, O_RDONLY)) == -1) {
+ DBGPRINTF("error reading '%s'\n", namebuf);
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+ if((lenRead = read(fd, buf, lenBuf - 1)) == -1) {
+ DBGPRINTF("error reading file data for '%s'\n", namebuf);
+ close(fd);
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+
+ /* we strip after the first \n */
+ for(i = 0 ; i < lenRead ; ++i) {
+ if(buf[i] == '\n')
+ break;
+ else if(iscntrl(buf[i]))
+ buf[i] = ' ';
+ }
+ buf[i] = '\0';
+ *lenProp = i;
+
+ close(fd);
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* read the exe trusted property path (so far, /proc fs only)
+ */
+static rsRetVal
+getTrustedExe(struct ucred *cred, uchar *buf, size_t lenBuf, int* lenProp)
+{
+ int lenRead;
+ char namebuf[1024];
+ DEFiRet;
+
+ if(snprintf(namebuf, sizeof(namebuf), "/proc/%lu/exe", (long unsigned) cred->pid)
+ >= (int) sizeof(namebuf)) {
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+
+ if((lenRead = readlink(namebuf, (char*)buf, lenBuf - 1)) == -1) {
+ DBGPRINTF("error reading link '%s'\n", namebuf);
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+
+ buf[lenRead] = '\0';
+ *lenProp = lenRead;
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* copy a trusted property in escaped mode. That is, the property can contain
+ * any character and so it must be properly quoted AND escaped.
+ * It is assumed the output buffer is large enough. Returns the number of
+ * characters added.
+ */
+static int
+copyescaped(uchar *dstbuf, uchar *inbuf, int inlen)
+{
+ int iDst, iSrc;
+
+ *dstbuf = '"';
+ for(iDst=1, iSrc=0 ; iSrc < inlen ; ++iDst, ++iSrc) {
+ if(inbuf[iSrc] == '"' || inbuf[iSrc] == '\\') {
+ dstbuf[iDst++] = '\\';
+ }
+ dstbuf[iDst] = inbuf[iSrc];
+ }
+ dstbuf[iDst++] = '"';
+ return iDst;
+}
+
+
+/* submit received message to the queue engine
+ * We now parse the message according to expected format so that we
+ * can also mangle it if necessary.
+ */
+static rsRetVal
+SubmitMsg(uchar *pRcv, int lenRcv, lstn_t *pLstn, struct ucred *cred, struct timeval *ts)
+{
+ smsg_t *pMsg = NULL;
+ int lenMsg;
+ int offs;
+ int i;
+ uchar *parse;
+ syslog_pri_t pri;
+ uchar bufParseTAG[CONF_TAG_MAXSIZE];
+ struct syslogTime st;
+ time_t tt;
+ ratelimit_t *ratelimiter = NULL;
+ struct syslogTime dummyTS;
+ DEFiRet;
+
+ if(pLstn->bDiscardOwnMsgs && cred != NULL && cred->pid == glblGetOurPid()) {
+ DBGPRINTF("imuxsock: discarding message from our own pid\n");
+ FINALIZE;
+ }
+
+ /* TODO: handle format errors?? */
+ /* we need to parse the pri first, because we need the severity for
+ * rate-limiting as well.
+ */
+ parse = pRcv;
+ lenMsg = lenRcv;
+ offs = 1; /* '<' */
+
+ parse++;
+ pri = 0;
+ while(offs < lenMsg && isdigit(*parse)) {
+ pri = pri * 10 + *parse - '0';
+ ++parse;
+ ++offs;
+ }
+
+ findRatelimiter(pLstn, cred, &ratelimiter); /* ignore error, better so than others... */
+
+ if(ts == NULL) {
+ datetime.getCurrTime(&st, &tt, TIME_IN_LOCALTIME);
+ } else {
+ datetime.timeval2syslogTime(ts, &st, TIME_IN_LOCALTIME);
+ tt = ts->tv_sec;
+ }
+
+#if 0 // TODO: think about stats counters (or wait for request...?)
+ if(ratelimiter != NULL && !withinRatelimit(ratelimiter, tt, cred->pid)) {
+ STATSCOUNTER_INC(ctrLostRatelimit, mutCtrLostRatelimit);
+ FINALIZE;
+ }
+#endif
+
+ /* we now create our own message object and submit it to the queue */
+ CHKiRet(msgConstructWithTime(&pMsg, &st, tt));
+
+ /* created trusted properties */
+ if(cred != NULL && pLstn->bAnnotate) {
+ uchar propBuf[1024];
+ int lenProp;
+
+ if (pLstn->bParseTrusted) {
+ struct json_object *json, *jval;
+
+#define CHKjson(operation, toBeFreed) \
+ if((operation) == NULL) { \
+ json_object_put(toBeFreed); \
+ ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY); \
+ }
+
+ CHKmalloc(json = json_object_new_object());
+ /* create value string, create field, and add it */
+ CHKjson(jval = json_object_new_int(cred->pid), json);
+ json_object_object_add(json, "pid", jval);
+ CHKjson(jval = json_object_new_int(cred->uid), json);
+ json_object_object_add(json, "uid", jval);
+ CHKjson(jval = json_object_new_int(cred->gid), json);
+ json_object_object_add(json, "gid", jval);
+ if(getTrustedProp(cred, "comm", propBuf, sizeof(propBuf), &lenProp) == RS_RET_OK) {
+ CHKjson(jval = json_object_new_string((char*)propBuf), json);
+ json_object_object_add(json, "appname", jval);
+ }
+ if(getTrustedExe(cred, propBuf, sizeof(propBuf), &lenProp) == RS_RET_OK) {
+ CHKjson(jval = json_object_new_string((char*)propBuf), json);
+ json_object_object_add(json, "exe", jval);
+ }
+ if(getTrustedProp(cred, "cmdline", propBuf, sizeof(propBuf), &lenProp) == RS_RET_OK) {
+ CHKjson(jval = json_object_new_string((char*)propBuf), json);
+ json_object_object_add(json, "cmd", jval);
+ }
+#undef CHKjson
+
+ /* as per lumberjack spec, these properties need to go into
+ * the CEE root.
+ */
+ msgAddJSON(pMsg, (uchar*)"!", json, 0, 0);
+
+ MsgSetRawMsg(pMsg, (char*)pRcv, lenRcv);
+ } else {
+ uchar msgbuf[8192];
+ uchar *pmsgbuf = msgbuf;
+ int toffs; /* offset for trusted properties */
+
+ if((unsigned) (lenRcv + 4096) >= sizeof(msgbuf)) {
+ CHKmalloc(pmsgbuf = malloc(lenRcv+4096));
+ }
+
+ memcpy(pmsgbuf, pRcv, lenRcv);
+ memcpy(pmsgbuf+lenRcv, " @[", 3);
+ toffs = lenRcv + 3; /* next free location */
+ lenProp = snprintf((char*)propBuf, sizeof(propBuf), "_PID=%lu _UID=%lu _GID=%lu",
+ (long unsigned) cred->pid, (long unsigned) cred->uid,
+ (long unsigned) cred->gid);
+ memcpy(pmsgbuf+toffs, propBuf, lenProp);
+ toffs = toffs + lenProp;
+
+ if(getTrustedProp(cred, "comm", propBuf, sizeof(propBuf), &lenProp) == RS_RET_OK) {
+ memcpy(pmsgbuf+toffs, " _COMM=", 7);
+ memcpy(pmsgbuf+toffs+7, propBuf, lenProp);
+ toffs = toffs + 7 + lenProp;
+ }
+ if(getTrustedExe(cred, propBuf, sizeof(propBuf), &lenProp) == RS_RET_OK) {
+ memcpy(pmsgbuf+toffs, " _EXE=", 6);
+ memcpy(pmsgbuf+toffs+6, propBuf, lenProp);
+ toffs = toffs + 6 + lenProp;
+ }
+ if(getTrustedProp(cred, "cmdline", propBuf, sizeof(propBuf), &lenProp) == RS_RET_OK) {
+ memcpy(pmsgbuf+toffs, " _CMDLINE=", 10);
+ toffs = toffs + 10 +
+ copyescaped(pmsgbuf+toffs+10, propBuf, lenProp);
+ }
+
+ /* finalize string */
+ pmsgbuf[toffs] = ']';
+ pmsgbuf[toffs+1] = '\0';
+
+ MsgSetRawMsg(pMsg, (char*)pmsgbuf, toffs + 1);
+ if (pmsgbuf != msgbuf) {
+ free(pmsgbuf);
+ }
+ }
+ } else {
+ /* just add the unmodified message */
+ MsgSetRawMsg(pMsg, (char*)pRcv, lenRcv);
+ }
+
+ MsgSetFlowControlType(pMsg, pLstn->flowCtl);
+ MsgSetInputName(pMsg, pInputName);
+ if(pLstn->bParseHost) {
+ pMsg->msgFlags = pLstn->flags | PARSE_HOSTNAME;
+ } else {
+ pMsg->msgFlags = pLstn->flags;
+ }
+
+ if(pLstn->bUseSpecialParser) {
+ /* this is the legacy "log socket" parser which was written on the assumption
+ * that the log socket format would be fixed. While many folks said so, it
+ * seems to be different in practice, and this is why we now have choices...
+ * rgerhards, 2015-03-03
+ */
+ parser.SanitizeMsg(pMsg);
+ lenMsg = pMsg->iLenRawMsg - offs; /* SanitizeMsg() may have changed the size */
+ msgSetPRI(pMsg, pri);
+ MsgSetAfterPRIOffs(pMsg, offs);
+
+ parse++; lenMsg--; /* '>' */
+ if(ts == NULL) {
+ if((pLstn->flags & IGNDATE)) {
+ /* in this case, we still need to find out if we have a valid
+ * datestamp or not .. and advance the parse pointer accordingly.
+ */
+ if (datetime.ParseTIMESTAMP3339(&dummyTS, &parse, &lenMsg) != RS_RET_OK) {
+ datetime.ParseTIMESTAMP3164(&dummyTS, &parse, &lenMsg,
+ NO_PARSE3164_TZSTRING, NO_PERMIT_YEAR_AFTER_TIME);
+ }
+ } else {
+ if(datetime.ParseTIMESTAMP3339(&(pMsg->tTIMESTAMP), &parse, &lenMsg) != RS_RET_OK &&
+ datetime.ParseTIMESTAMP3164(&(pMsg->tTIMESTAMP), &parse, &lenMsg,
+ NO_PARSE3164_TZSTRING, NO_PERMIT_YEAR_AFTER_TIME) != RS_RET_OK) {
+ DBGPRINTF("we have a problem, invalid timestamp in msg!\n");
+ }
+ }
+ } else { /* if we pulled the time from the system, we need to update the message text */
+ uchar *tmpParse = parse; /* just to check correctness of TS */
+ if(datetime.ParseTIMESTAMP3339(&dummyTS, &tmpParse, &lenMsg) == RS_RET_OK ||
+ datetime.ParseTIMESTAMP3164(&dummyTS, &tmpParse, &lenMsg, NO_PARSE3164_TZSTRING,
+ NO_PERMIT_YEAR_AFTER_TIME) == RS_RET_OK) {
+ /* We modify the message only if it contained a valid timestamp,
+ otherwise we do not touch it at all. */
+ datetime.formatTimestamp3164(&st, (char*)parse, 0);
+ parse[15] = ' '; /* re-write \0 from fromatTimestamp3164 by SP */
+ /* update "counters" to reflect processed timestamp */
+ parse += 16;
+ }
+ }
+
+ /* pull tag */
+
+ i = 0;
+ while(lenMsg > 0 && *parse != ' ' && i < CONF_TAG_MAXSIZE - 1) {
+ bufParseTAG[i++] = *parse++;
+ --lenMsg;
+ }
+ bufParseTAG[i] = '\0'; /* terminate string */
+ if(pLstn->bWritePid)
+ fixPID(bufParseTAG, &i, cred);
+ MsgSetTAG(pMsg, bufParseTAG, i);
+ MsgSetMSGoffs(pMsg, pMsg->iLenRawMsg - lenMsg);
+ } else { /* we are configured to use regular parser chain */
+ pMsg->msgFlags |= NEEDS_PARSING;
+ }
+
+ MsgSetRcvFrom(pMsg, pLstn->hostName == NULL ? glbl.GetLocalHostNameProp() : pLstn->hostName);
+ CHKiRet(MsgSetRcvFromIP(pMsg, pLocalHostIP));
+ MsgSetRuleset(pMsg, pLstn->pRuleset);
+ ratelimitAddMsg(ratelimiter, NULL, pMsg);
+ STATSCOUNTER_INC(ctrSubmit, mutCtrSubmit);
+finalize_it:
+ if(iRet != RS_RET_OK) {
+ if(pMsg != NULL)
+ msgDestruct(&pMsg);
+ }
+ RETiRet;
+}
+
+
+/* This function receives data from a socket indicated to be ready
+ * to receive and submits the message received for processing.
+ * rgerhards, 2007-12-20
+ * Interface changed so that this function is passed the array index
+ * of the socket which is to be processed. This eases access to the
+ * growing number of properties. -- rgerhards, 2008-08-01
+ */
+static rsRetVal readSocket(lstn_t *pLstn)
+{
+ DEFiRet;
+ int iRcvd;
+ int iMaxLine;
+ struct msghdr msgh;
+ struct iovec msgiov;
+ struct ucred cred;
+ struct timeval ts;
+ int cred_set = 0;
+ int ts_set = 0;
+ uchar bufRcv[4096+1];
+ uchar *pRcv = NULL; /* receive buffer */
+# ifdef HAVE_SCM_CREDENTIALS
+ /* aux is a union rather than a direct char array to force alignment with cmsghdr */
+ union {
+ char buf[128];
+ struct cmsghdr cm;
+ } aux;
+# endif
+
+ assert(pLstn->fd >= 0);
+
+ iMaxLine = glbl.GetMaxLine(runConf);
+
+ /* we optimize performance: if iMaxLine is below 4K (which it is in almost all
+ * cases, we use a fixed buffer on the stack. Only if it is higher, heap memory
+ * is used. We could use alloca() to achive a similar aspect, but there are so
+ * many issues with alloca() that I do not want to take that route.
+ * rgerhards, 2008-09-02
+ */
+ if((size_t) iMaxLine < sizeof(bufRcv) - 1) {
+ pRcv = bufRcv;
+ } else {
+ CHKmalloc(pRcv = (uchar*) malloc(iMaxLine + 1));
+ }
+
+ memset(&msgh, 0, sizeof(msgh));
+ memset(&msgiov, 0, sizeof(msgiov));
+# ifdef HAVE_SCM_CREDENTIALS
+ if(pLstn->bUseCreds) {
+ memset(&aux, 0, sizeof(aux));
+ msgh.msg_control = &aux;
+ msgh.msg_controllen = sizeof(aux);
+ }
+# endif
+ msgiov.iov_base = (char*)pRcv;
+ msgiov.iov_len = iMaxLine;
+ msgh.msg_iov = &msgiov;
+ msgh.msg_iovlen = 1;
+/* AIXPORT : MSG_DONTWAIT not supported */
+#if defined (_AIX)
+#define MSG_DONTWAIT MSG_NONBLOCK
+#endif
+ iRcvd = recvmsg(pLstn->fd, &msgh, MSG_DONTWAIT);
+
+ DBGPRINTF("Message from UNIX socket: #%d, size %d\n", pLstn->fd, (int) iRcvd);
+ if(iRcvd > 0) {
+# if defined(HAVE_SCM_CREDENTIALS) || defined(HAVE_SO_TIMESTAMP)
+ if(pLstn->bUseCreds) {
+ struct cmsghdr *cm;
+ for(cm = CMSG_FIRSTHDR(&msgh); cm; cm = CMSG_NXTHDR(&msgh, cm)) {
+# ifdef HAVE_SCM_CREDENTIALS
+ if( pLstn->bUseCreds
+ && cm->cmsg_level == SOL_SOCKET && cm->cmsg_type == SCM_CREDENTIALS) {
+ memcpy(&cred, CMSG_DATA(cm), sizeof(cred));
+ cred_set = 1;
+ }
+# endif /* HAVE_SCM_CREDENTIALS */
+# if HAVE_SO_TIMESTAMP
+ if( pLstn->bUseSysTimeStamp
+ && cm->cmsg_level == SOL_SOCKET && cm->cmsg_type == SO_TIMESTAMP) {
+ memcpy(&ts, CMSG_DATA(cm), sizeof(ts));
+ ts_set = 1;
+ }
+# endif /* HAVE_SO_TIMESTAMP */
+ }
+ }
+# endif /* defined(HAVE_SCM_CREDENTIALS) || defined(HAVE_SO_TIMESTAMP) */
+ CHKiRet(SubmitMsg(pRcv, iRcvd, pLstn, (cred_set ? &cred : NULL), (ts_set ? &ts : NULL)));
+ } else if(iRcvd < 0 && errno != EINTR && errno != EAGAIN) {
+ char errStr[1024];
+ rs_strerror_r(errno, errStr, sizeof(errStr));
+ DBGPRINTF("UNIX socket error: %d = %s.\n", errno, errStr);
+ LogError(errno, NO_ERRCODE, "imuxsock: recvfrom UNIX");
+ }
+
+finalize_it:
+ if(pRcv != NULL && (size_t) iMaxLine >= sizeof(bufRcv) - 1)
+ free(pRcv);
+
+ RETiRet;
+}
+
+
+/* activate current listeners */
+static rsRetVal
+activateListeners(void)
+{
+ int actSocks;
+ int i;
+ DEFiRet;
+
+ /* Initialize the system socket only if it's in use */
+ if(startIndexUxLocalSockets == 0) {
+ /* first apply some config settings */
+ listeners[0].sockName = UCHAR_CONSTANT(_PATH_LOG);
+ if(runModConf->pLogSockName != NULL) {
+ listeners[0].sockName = runModConf->pLogSockName;
+ }
+#ifdef HAVE_LIBSYSTEMD
+ else if(sd_booted()) {
+ struct stat st;
+ if(stat(SYSTEMD_PATH_LOG, &st) != -1 && S_ISSOCK(st.st_mode)) {
+ listeners[0].sockName = (uchar*) SYSTEMD_PATH_LOG;
+ }
+ }
+#endif
+ if(runModConf->ratelimitIntervalSysSock > 0) {
+ if((listeners[0].ht = create_hashtable(100, hash_from_key_fn, key_equals_fn, NULL)) == NULL) {
+ /* in this case, we simply turn of rate-limiting */
+ LogError(0, NO_ERRCODE, "imuxsock: turning off rate limiting because "
+ "we could not create hash table\n");
+ runModConf->ratelimitIntervalSysSock = 0;
+ }
+ } else {
+ listeners[0].ht = NULL;
+ }
+ listeners[0].fd = -1;
+ listeners[0].pRuleset = NULL;
+ listeners[0].hostName = NULL;
+ listeners[0].bParseHost = 0;
+ listeners[0].bCreatePath = 0;
+ listeners[0].ratelimitInterval = runModConf->ratelimitIntervalSysSock;
+ listeners[0].ratelimitBurst = runModConf->ratelimitBurstSysSock;
+ listeners[0].ratelimitSev = runModConf->ratelimitSeveritySysSock;
+ listeners[0].bUseCreds = (runModConf->bWritePidSysSock || runModConf->ratelimitIntervalSysSock
+ || runModConf->bAnnotateSysSock || runModConf->bDiscardOwnMsgs
+ || runModConf->bUseSysTimeStamp) ? 1 : 0;
+ listeners[0].bWritePid = runModConf->bWritePidSysSock;
+ listeners[0].bAnnotate = runModConf->bAnnotateSysSock;
+ listeners[0].bParseTrusted = runModConf->bParseTrusted;
+ listeners[0].bParseHost = runModConf->bParseHost;
+ listeners[0].bUseSpecialParser = runModConf->bUseSpecialParser;
+ listeners[0].bDiscardOwnMsgs = runModConf->bDiscardOwnMsgs;
+ listeners[0].bUnlink = runModConf->bUnlink;
+ listeners[0].bUseSysTimeStamp = runModConf->bUseSysTimeStamp;
+ listeners[0].flags = runModConf->bIgnoreTimestamp ? IGNDATE : NOFLAG;
+ listeners[0].flowCtl = runModConf->bUseFlowCtl ? eFLOWCTL_LIGHT_DELAY : eFLOWCTL_NO_DELAY;
+ CHKiRet(ratelimitNew(&listeners[0].dflt_ratelimiter, "imuxsock", NULL));
+ ratelimitSetLinuxLike(listeners[0].dflt_ratelimiter,
+ listeners[0].ratelimitInterval,
+ listeners[0].ratelimitBurst);
+ ratelimitSetSeverity(listeners[0].dflt_ratelimiter,listeners[0].ratelimitSev);
+ }
+
+#ifdef HAVE_LIBSYSTEMD
+ sd_fds = sd_listen_fds(0);
+ if(sd_fds < 0) {
+ LogError(-sd_fds, NO_ERRCODE, "imuxsock: Failed to acquire systemd socket");
+ ABORT_FINALIZE(RS_RET_ERR_CRE_AFUX);
+ }
+#endif
+
+ /* initialize and return if will run or not */
+ actSocks = 0;
+ for (i = startIndexUxLocalSockets ; i < nfd ; i++) {
+ if(openLogSocket(&(listeners[i])) == RS_RET_OK) {
+ ++actSocks;
+ DBGPRINTF("imuxsock: Opened UNIX socket '%s' (fd %d).\n",
+ listeners[i].sockName, listeners[i].fd);
+ }
+ }
+
+ if(actSocks == 0) {
+ LogError(0, RS_RET_ERR, "imuxsock does not run because we could not "
+ "acquire any socket\n");
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+
+finalize_it:
+ RETiRet;
+}
+
+
+
+BEGINbeginCnfLoad
+CODESTARTbeginCnfLoad
+ loadModConf = pModConf;
+ pModConf->pConf = pConf;
+ /* init our settings */
+ pModConf->pLogSockName = NULL;
+ pModConf->bOmitLocalLogging = 0;
+ pModConf->bIgnoreTimestamp = 1;
+ pModConf->bUseFlowCtl = 0;
+ pModConf->bUseSysTimeStamp = 1;
+ pModConf->bWritePidSysSock = 0;
+ pModConf->bAnnotateSysSock = 0;
+ pModConf->bParseTrusted = 0;
+ pModConf->bParseHost = UNSET;
+ pModConf->bUseSpecialParser = DFLT_bUseSpecialParser;
+ /* if we do not process internal messages, we will see messages
+ * from ourselves, and so we need to permit this.
+ */
+ pModConf->bDiscardOwnMsgs = pConf->globals.bProcessInternalMessages;
+ pModConf->bUnlink = 1;
+ pModConf->ratelimitIntervalSysSock = DFLT_ratelimitInterval;
+ pModConf->ratelimitBurstSysSock = DFLT_ratelimitBurst;
+ pModConf->ratelimitSeveritySysSock = DFLT_ratelimitSeverity;
+ bLegacyCnfModGlobalsPermitted = 1;
+ /* reset legacy config vars */
+ resetConfigVariables(NULL, NULL);
+ENDbeginCnfLoad
+
+
+BEGINsetModCnf
+ struct cnfparamvals *pvals = NULL;
+ int i;
+CODESTARTsetModCnf
+ pvals = nvlstGetParams(lst, &modpblk, NULL);
+ if(pvals == NULL) {
+ LogError(0, RS_RET_MISSING_CNFPARAMS, "error processing module "
+ "config parameters [module(...)]");
+ ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS);
+ }
+
+ if(Debug) {
+ dbgprintf("module (global) param blk for imuxsock:\n");
+ cnfparamsPrint(&modpblk, pvals);
+ }
+
+ for(i = 0 ; i < modpblk.nParams ; ++i) {
+ if(!pvals[i].bUsed)
+ continue;
+ if(!strcmp(modpblk.descr[i].name, "syssock.use")) {
+ loadModConf->bOmitLocalLogging = ((int) pvals[i].val.d.n) ? 0 : 1;
+ } else if(!strcmp(modpblk.descr[i].name, "syssock.name")) {
+ loadModConf->pLogSockName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
+ } else if(!strcmp(modpblk.descr[i].name, "syssock.ignoretimestamp")) {
+ loadModConf->bIgnoreTimestamp = (int) pvals[i].val.d.n;
+ } else if(!strcmp(modpblk.descr[i].name, "syssock.ignoreownmessages")) {
+ loadModConf->bDiscardOwnMsgs = (int) pvals[i].val.d.n;
+ } else if(!strcmp(modpblk.descr[i].name, "syssock.unlink")) {
+ loadModConf->bUnlink = (int) pvals[i].val.d.n;
+ } else if(!strcmp(modpblk.descr[i].name, "syssock.flowcontrol")) {
+ loadModConf->bUseFlowCtl = (int) pvals[i].val.d.n;
+ } else if(!strcmp(modpblk.descr[i].name, "syssock.usesystimestamp")) {
+ loadModConf->bUseSysTimeStamp = (int) pvals[i].val.d.n;
+ } else if(!strcmp(modpblk.descr[i].name, "syssock.annotate")) {
+ loadModConf->bAnnotateSysSock = (int) pvals[i].val.d.n;
+ } else if(!strcmp(modpblk.descr[i].name, "syssock.parsetrusted")) {
+ loadModConf->bParseTrusted = (int) pvals[i].val.d.n;
+ } else if(!strcmp(modpblk.descr[i].name, "syssock.parsehostname")) {
+ loadModConf->bParseHost = (int) pvals[i].val.d.n;
+ } else if(!strcmp(modpblk.descr[i].name, "syssock.usespecialparser")) {
+ loadModConf->bUseSpecialParser = (int) pvals[i].val.d.n;
+ } else if(!strcmp(modpblk.descr[i].name, "syssock.usepidfromsystem")) {
+ loadModConf->bWritePidSysSock = (int) pvals[i].val.d.n;
+ } else if(!strcmp(modpblk.descr[i].name, "syssock.ratelimit.interval")) {
+ loadModConf->ratelimitIntervalSysSock = (unsigned int) pvals[i].val.d.n;
+ } else if(!strcmp(modpblk.descr[i].name, "syssock.ratelimit.burst")) {
+ loadModConf->ratelimitBurstSysSock = (unsigned int) pvals[i].val.d.n;
+ } else if(!strcmp(modpblk.descr[i].name, "syssock.ratelimit.severity")) {
+ loadModConf->ratelimitSeveritySysSock = (int) pvals[i].val.d.n;
+ } else {
+ dbgprintf("imuxsock: program error, non-handled "
+ "param '%s' in beginCnfLoad\n", modpblk.descr[i].name);
+ }
+ }
+
+ /* disable legacy module-global config directives */
+ bLegacyCnfModGlobalsPermitted = 0;
+ loadModConf->configSetViaV2Method = 1;
+
+finalize_it:
+ if(pvals != NULL)
+ cnfparamvalsDestruct(pvals, &modpblk);
+ENDsetModCnf
+
+
+BEGINnewInpInst
+ struct cnfparamvals *pvals;
+ instanceConf_t *inst;
+ int i;
+CODESTARTnewInpInst
+ DBGPRINTF("newInpInst (imuxsock)\n");
+
+ pvals = nvlstGetParams(lst, &inppblk, NULL);
+ if(pvals == NULL) {
+ LogError(0, RS_RET_MISSING_CNFPARAMS,
+ "imuxsock: required parameter are missing\n");
+ ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS);
+ }
+
+ if(Debug) {
+ dbgprintf("input param blk in imuxsock:\n");
+ cnfparamsPrint(&inppblk, pvals);
+ }
+
+ CHKiRet(createInstance(&inst));
+
+ for(i = 0 ; i < inppblk.nParams ; ++i) {
+ if(!pvals[i].bUsed)
+ continue;
+ if(!strcmp(inppblk.descr[i].name, "socket")) {
+ inst->sockName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
+ } else if(!strcmp(inppblk.descr[i].name, "createpath")) {
+ inst->bCreatePath = (int) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "parsetrusted")) {
+ inst->bParseTrusted = (int) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "ignoreownmessages")) {
+ inst->bDiscardOwnMsgs = (int) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "unlink")) {
+ inst->bUnlink = (int) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "hostname")) {
+ inst->pLogHostName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
+ } else if(!strcmp(inppblk.descr[i].name, "ignoretimestamp")) {
+ inst->bIgnoreTimestamp = (int) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "flowcontrol")) {
+ inst->bUseFlowCtl = (int) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "usesystimestamp")) {
+ inst->bUseSysTimeStamp = (int) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "annotate")) {
+ inst->bAnnotate = (int) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "usepidfromsystem")) {
+ inst->bWritePid = (int) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "parsehostname")) {
+ inst->bParseHost = (int) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "usespecialparser")) {
+ inst->bUseSpecialParser = (int) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "ruleset")) {
+ inst->pszBindRuleset = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
+ } else if(!strcmp(inppblk.descr[i].name, "ratelimit.interval")) {
+ inst->ratelimitInterval = (unsigned int) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "ratelimit.burst")) {
+ inst->ratelimitBurst = (unsigned int) pvals[i].val.d.n;
+ } else if(!strcmp(inppblk.descr[i].name, "ratelimit.severity")) {
+ inst->ratelimitSeverity = (int) pvals[i].val.d.n;
+ } else {
+ dbgprintf("imuxsock: program error, non-handled "
+ "param '%s'\n", inppblk.descr[i].name);
+ }
+ }
+finalize_it:
+CODE_STD_FINALIZERnewInpInst
+ cnfparamvalsDestruct(pvals, &inppblk);
+ENDnewInpInst
+
+
+BEGINendCnfLoad
+CODESTARTendCnfLoad
+ if(!loadModConf->configSetViaV2Method) {
+ /* persist module-specific settings from legacy config system */
+ /* these are used to initialize the system log socket (listeners[0]) */
+ loadModConf->bOmitLocalLogging = cs.bOmitLocalLogging;
+ loadModConf->pLogSockName = cs.pLogSockName;
+ loadModConf->bIgnoreTimestamp = cs.bIgnoreTimestampSysSock;
+ loadModConf->bUseSysTimeStamp = cs.bUseSysTimeStampSysSock;
+ loadModConf->bUseFlowCtl = cs.bUseFlowCtlSysSock;
+ loadModConf->bAnnotateSysSock = cs.bAnnotateSysSock;
+ loadModConf->bWritePidSysSock = cs.bWritePidSysSock;
+ loadModConf->bParseTrusted = cs.bParseTrusted;
+ loadModConf->ratelimitIntervalSysSock = cs.ratelimitIntervalSysSock;
+ loadModConf->ratelimitBurstSysSock = cs.ratelimitBurstSysSock;
+ loadModConf->ratelimitSeveritySysSock = cs.ratelimitSeveritySysSock;
+ }
+
+ loadModConf = NULL; /* done loading */
+ /* free legacy config vars */
+ free(cs.pLogHostName);
+ cs.pLogSockName = NULL;
+ cs.pLogHostName = NULL;
+ENDendCnfLoad
+
+
+/* function to generate error message if framework does not find requested ruleset */
+static void
+std_checkRuleset_genErrMsg(__attribute__((unused)) modConfData_t *modConf, instanceConf_t *inst)
+{
+ LogError(0, NO_ERRCODE, "imuxsock: ruleset '%s' for socket %s not found - "
+ "using default ruleset instead", inst->pszBindRuleset,
+ inst->sockName);
+}
+BEGINcheckCnf
+ instanceConf_t *inst;
+CODESTARTcheckCnf
+ for(inst = pModConf->root ; inst != NULL ; inst = inst->next) {
+ std_checkRuleset(pModConf, inst);
+ }
+ENDcheckCnf
+
+
+BEGINactivateCnfPrePrivDrop
+ instanceConf_t *inst;
+ int nLstn;
+ int i;
+CODESTARTactivateCnfPrePrivDrop
+ runModConf = pModConf;
+# ifdef OS_SOLARIS
+ /* under solaris, we must NEVER process the local log socket, because
+ * it is implemented there differently. If we used it, we would actually
+ * delete it and render the system partly unusable. So don't do that.
+ * rgerhards, 2010-03-26
+ */
+ startIndexUxLocalSockets = 1;
+# else
+ startIndexUxLocalSockets = runModConf->bOmitLocalLogging ? 1 : 0;
+# endif
+ /* we first calculate the number of listeners so that we can
+ * appropriately size the listener array. Note that we will
+ * always allocate memory for the system log socket.
+ */
+ nLstn = 0;
+ for(inst = runModConf->root ; inst != NULL ; inst = inst->next) {
+ ++nLstn;
+ }
+ if(nLstn > 0 || startIndexUxLocalSockets == 0) {
+ DBGPRINTF("imuxsock: allocating memory for %d listeners\n", nLstn);
+ lstn_t *const listeners_new = realloc(listeners, (1+nLstn)*sizeof(lstn_t));
+ CHKmalloc(listeners_new);
+ listeners = listeners_new;
+ for(i = 1 ; i < nLstn ; ++i) {
+ listeners[i].sockName = NULL;
+ listeners[i].fd = -1;
+ }
+ for(inst = runModConf->root ; inst != NULL ; inst = inst->next) {
+ addListner(inst);
+ }
+ CHKiRet(activateListeners());
+ }
+finalize_it:
+ENDactivateCnfPrePrivDrop
+
+
+BEGINactivateCnf
+CODESTARTactivateCnf
+ENDactivateCnf
+
+
+BEGINfreeCnf
+ instanceConf_t *inst, *del;
+CODESTARTfreeCnf
+ free(pModConf->pLogSockName);
+ for(inst = pModConf->root ; inst != NULL ; ) {
+ free(inst->sockName);
+ free(inst->pszBindRuleset);
+ free(inst->pLogHostName);
+ del = inst;
+ inst = inst->next;
+ free(del);
+ }
+ENDfreeCnf
+
+
+/* This function is called to gather input. */
+BEGINrunInput
+ int nfds;
+ int i;
+CODESTARTrunInput
+ struct pollfd *const pollfds = calloc(nfd, sizeof(struct pollfd));
+ CHKmalloc(pollfds);
+ if(startIndexUxLocalSockets == 1 && nfd == 1) {
+ /* No sockets were configured, no reason to run. */
+ ABORT_FINALIZE(RS_RET_OK);
+ }
+ if(startIndexUxLocalSockets == 1) {
+ pollfds[0].fd = -1;
+ }
+ for (i = startIndexUxLocalSockets; i < nfd; i++) {
+ pollfds[i].fd = listeners[i].fd;
+ pollfds[i].events = POLLIN;
+ }
+
+ /* this is an endless loop - it is terminated when the thread is
+ * signalled to do so.
+ */
+ while(1) {
+ DBGPRINTF("--------imuxsock calling poll() on %d fds\n", nfd);
+
+ nfds = poll(pollfds, nfd, -1);
+ if(glbl.GetGlobalInputTermState() == 1)
+ break; /* terminate input! */
+
+ if(nfds < 0) {
+ if(errno == EINTR) {
+ DBGPRINTF("imuxsock: EINTR occurred\n");
+ } else {
+ LogMsg(errno, RS_RET_POLL_ERR, LOG_WARNING, "imuxsock: poll "
+ "system call failed, may cause further troubles");
+ }
+ nfds = 0;
+ }
+
+ for (i = startIndexUxLocalSockets ; i < nfd && nfds > 0; i++) {
+ if(glbl.GetGlobalInputTermState() == 1)
+ ABORT_FINALIZE(RS_RET_FORCE_TERM); /* terminate input! */
+ if(pollfds[i].revents & POLLIN) {
+ readSocket(&(listeners[i]));
+ --nfds; /* indicate we have processed one */
+ }
+ }
+ }
+
+finalize_it:
+ free(pollfds);
+ENDrunInput
+
+
+BEGINwillRun
+CODESTARTwillRun
+ENDwillRun
+
+
+BEGINafterRun
+ int i;
+CODESTARTafterRun
+ /* do cleanup here */
+ if(startIndexUxLocalSockets == 1 && nfd == 1) {
+ /* No sockets were configured, no cleanup needed. */
+ return RS_RET_OK;
+ }
+
+ /* Close the UNIX sockets. */
+ for (i = 0; i < nfd; i++)
+ if (listeners[i].fd != -1)
+ close(listeners[i].fd);
+
+ /* Clean-up files. */
+ for(i = startIndexUxLocalSockets; i < nfd; i++)
+ if (listeners[i].sockName && listeners[i].fd != -1) {
+ /* If systemd passed us a socket it is systemd's job to clean it up.
+ * Do not unlink it -- we will get same socket (node) from systemd
+ * e.g. on restart again.
+ */
+ if (sd_fds > 0
+# ifdef HAVE_LIBSYSTEMD
+ && listeners[i].fd >= SD_LISTEN_FDS_START &&
+ listeners[i].fd < SD_LISTEN_FDS_START + sd_fds
+# endif
+ )
+ continue;
+
+ if(listeners[i].bUnlink) {
+ DBGPRINTF("imuxsock: unlinking unix socket file[%d] %s\n", i, listeners[i].sockName);
+ unlink((char*) listeners[i].sockName);
+ }
+ }
+
+ discardLogSockets();
+ nfd = 1;
+ENDafterRun
+
+
+BEGINmodExit
+CODESTARTmodExit
+ free(listeners);
+ if(pInputName != NULL)
+ prop.Destruct(&pInputName);
+
+ statsobj.Destruct(&modStats);
+
+ objRelease(parser, CORE_COMPONENT);
+ objRelease(glbl, CORE_COMPONENT);
+ objRelease(prop, CORE_COMPONENT);
+ objRelease(statsobj, CORE_COMPONENT);
+ objRelease(datetime, CORE_COMPONENT);
+ objRelease(ruleset, CORE_COMPONENT);
+ENDmodExit
+
+
+BEGINisCompatibleWithFeature
+CODESTARTisCompatibleWithFeature
+ if(eFeat == sFEATURENonCancelInputTermination)
+ iRet = RS_RET_OK;
+ENDisCompatibleWithFeature
+
+
+BEGINqueryEtryPt
+CODESTARTqueryEtryPt
+CODEqueryEtryPt_STD_IMOD_QUERIES
+CODEqueryEtryPt_STD_CONF2_QUERIES
+CODEqueryEtryPt_STD_CONF2_setModCnf_QUERIES
+CODEqueryEtryPt_STD_CONF2_PREPRIVDROP_QUERIES
+CODEqueryEtryPt_STD_CONF2_IMOD_QUERIES
+CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES
+ENDqueryEtryPt
+
+static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
+{
+ free(cs.pLogSockName);
+ cs.pLogSockName = NULL;
+ free(cs.pLogHostName);
+ cs.bOmitLocalLogging = 0;
+ cs.pLogHostName = NULL;
+ cs.bIgnoreTimestamp = 1;
+ cs.bIgnoreTimestampSysSock = 1;
+ cs.bUseFlowCtl = 0;
+ cs.bUseFlowCtlSysSock = 0;
+ cs.bUseSysTimeStamp = 1;
+ cs.bUseSysTimeStampSysSock = 1;
+ cs.bWritePid = 0;
+ cs.bWritePidSysSock = 0;
+ cs.bAnnotate = 0;
+ cs.bAnnotateSysSock = 0;
+ cs.bParseTrusted = 0;
+ cs.bCreatePath = DFLT_bCreatePath;
+ cs.ratelimitInterval = DFLT_ratelimitInterval;
+ cs.ratelimitIntervalSysSock = DFLT_ratelimitInterval;
+ cs.ratelimitBurst = DFLT_ratelimitBurst;
+ cs.ratelimitBurstSysSock = DFLT_ratelimitBurst;
+ cs.ratelimitSeverity = DFLT_ratelimitSeverity;
+ cs.ratelimitSeveritySysSock = DFLT_ratelimitSeverity;
+
+ return RS_RET_OK;
+}
+
+
+BEGINmodInit()
+CODESTARTmodInit
+ *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
+CODEmodInit_QueryRegCFSLineHdlr
+ CHKiRet(objUse(glbl, CORE_COMPONENT));
+ CHKiRet(objUse(net, CORE_COMPONENT));
+ CHKiRet(objUse(prop, CORE_COMPONENT));
+ CHKiRet(objUse(statsobj, CORE_COMPONENT));
+ CHKiRet(objUse(datetime, CORE_COMPONENT));
+ CHKiRet(objUse(parser, CORE_COMPONENT));
+ CHKiRet(objUse(ruleset, CORE_COMPONENT));
+
+ DBGPRINTF("imuxsock version %s initializing\n", PACKAGE_VERSION);
+
+ /* init legacy config vars */
+ cs.pLogSockName = NULL;
+ cs.pLogHostName = NULL; /* host name to use with this socket */
+
+ /* we need to create the inputName property (only once during our lifetime) */
+ CHKiRet(prop.Construct(&pInputName));
+ CHKiRet(prop.SetString(pInputName, UCHAR_CONSTANT("imuxsock"), sizeof("imuxsock") - 1));
+ CHKiRet(prop.ConstructFinalize(pInputName));
+
+ /* right now, glbl does not permit per-instance IP address notation. As long as this
+ * is the case, it is OK to query the HostIP once here at this location. HOWEVER, the
+ * whole concept is not 100% clean and needs to be addressed on a higher layer.
+ * TODO / rgerhards, 2012-04-11
+ */
+ pLocalHostIP = glbl.GetLocalHostIP();
+
+ /* register config file handlers */
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensocketignoremsgtimestamp", 0, eCmdHdlrBinary,
+ NULL, &cs.bIgnoreTimestamp, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensockethostname", 0, eCmdHdlrGetWord,
+ NULL, &cs.pLogHostName, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensocketflowcontrol", 0, eCmdHdlrBinary,
+ NULL, &cs.bUseFlowCtl, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensocketannotate", 0, eCmdHdlrBinary,
+ NULL, &cs.bAnnotate, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensocketcreatepath", 0, eCmdHdlrBinary,
+ NULL, &cs.bCreatePath, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensocketusesystimestamp", 0, eCmdHdlrBinary,
+ NULL, &cs.bUseSysTimeStamp, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"addunixlistensocket", 0, eCmdHdlrGetWord,
+ addInstance, NULL, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensocketusepidfromsystem", 0, eCmdHdlrBinary,
+ NULL, &cs.bWritePid, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"imuxsockratelimitinterval", 0, eCmdHdlrInt,
+ NULL, &cs.ratelimitInterval, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"imuxsockratelimitburst", 0, eCmdHdlrInt,
+ NULL, &cs.ratelimitBurst, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"imuxsockratelimitseverity", 0, eCmdHdlrInt,
+ NULL, &cs.ratelimitSeverity, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler,
+ resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
+ /* the following one is a (dirty) trick: the system log socket is not added via
+ * an "addUnixListenSocket" config format. As such, it's properties can not be modified
+ * via $InputUnixListenSocket*". So we need to add a special directive
+ * for that. We should revisit all of that once we have the new config format...
+ * rgerhards, 2008-03-06
+ */
+ CHKiRet(regCfSysLineHdlr2((uchar *)"omitlocallogging", 0, eCmdHdlrBinary,
+ NULL, &cs.bOmitLocalLogging, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted));
+ CHKiRet(regCfSysLineHdlr2((uchar *)"systemlogsocketname", 0, eCmdHdlrGetWord,
+ NULL, &cs.pLogSockName, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted));
+ CHKiRet(regCfSysLineHdlr2((uchar *)"systemlogsocketignoremsgtimestamp", 0, eCmdHdlrBinary,
+ NULL, &cs.bIgnoreTimestampSysSock, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted));
+ CHKiRet(regCfSysLineHdlr2((uchar *)"systemlogsocketflowcontrol", 0, eCmdHdlrBinary,
+ NULL, &cs.bUseFlowCtlSysSock, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted));
+ CHKiRet(regCfSysLineHdlr2((uchar *)"systemlogusesystimestamp", 0, eCmdHdlrBinary,
+ NULL, &cs.bUseSysTimeStampSysSock, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted));
+ CHKiRet(regCfSysLineHdlr2((uchar *)"systemlogsocketannotate", 0, eCmdHdlrBinary,
+ NULL, &cs.bAnnotateSysSock, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted));
+ CHKiRet(regCfSysLineHdlr2((uchar *)"systemlogparsetrusted", 0, eCmdHdlrBinary,
+ NULL, &cs.bParseTrusted, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted));
+ CHKiRet(regCfSysLineHdlr2((uchar *)"systemlogusepidfromsystem", 0, eCmdHdlrBinary,
+ NULL, &cs.bWritePidSysSock, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted));
+ CHKiRet(regCfSysLineHdlr2((uchar *)"systemlogratelimitinterval", 0, eCmdHdlrInt,
+ NULL, &cs.ratelimitIntervalSysSock, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted));
+ CHKiRet(regCfSysLineHdlr2((uchar *)"systemlogratelimitburst", 0, eCmdHdlrInt,
+ NULL, &cs.ratelimitBurstSysSock, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted));
+ CHKiRet(regCfSysLineHdlr2((uchar *)"systemlogratelimitseverity", 0, eCmdHdlrInt,
+ NULL, &cs.ratelimitSeveritySysSock, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted));
+
+ /* support statistics gathering */
+ CHKiRet(statsobj.Construct(&modStats));
+ CHKiRet(statsobj.SetName(modStats, UCHAR_CONSTANT("imuxsock")));
+ CHKiRet(statsobj.SetOrigin(modStats, UCHAR_CONSTANT("imuxsock")));
+ STATSCOUNTER_INIT(ctrSubmit, mutCtrSubmit);
+ CHKiRet(statsobj.AddCounter(modStats, UCHAR_CONSTANT("submitted"),
+ ctrType_IntCtr, CTR_FLAG_RESETTABLE, &ctrSubmit));
+ STATSCOUNTER_INIT(ctrLostRatelimit, mutCtrLostRatelimit);
+ CHKiRet(statsobj.AddCounter(modStats, UCHAR_CONSTANT("ratelimit.discarded"),
+ ctrType_IntCtr, CTR_FLAG_RESETTABLE, &ctrLostRatelimit));
+ STATSCOUNTER_INIT(ctrNumRatelimiters, mutCtrNumRatelimiters);
+ CHKiRet(statsobj.AddCounter(modStats, UCHAR_CONSTANT("ratelimit.numratelimiters"),
+ ctrType_IntCtr, CTR_FLAG_RESETTABLE, &ctrNumRatelimiters));
+ CHKiRet(statsobj.ConstructFinalize(modStats));
+
+ENDmodInit