/* mmsnmptrapd.c * This is a message modification module. It takes messages generated * from snmptrapd and modifies them so that the look like they * originated from the real originator. * * NOTE: read comments in module-template.h for details on the calling interface! * * File begun on 2011-05-05 by RGerhards * * Copyright 2011 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 . * * A copy of the GPL can be found in the file "COPYING" in this distribution. */ #include "config.h" #include "rsyslog.h" #include #include #include #include #include #include #include #include #include #include #include #include "conf.h" #include "msg.h" #include "syslogd-types.h" #include "template.h" #include "module-template.h" #include "errmsg.h" #include "cfsysline.h" #include "unicode-helper.h" #include "dirty.h" MODULE_TYPE_OUTPUT MODULE_TYPE_NOKEEP static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal); /* static data */ DEFobjCurrIf(errmsg); /* internal structures */ DEF_OMOD_STATIC_DATA typedef struct _instanceData { uchar *pszTagName; uchar *pszTagID; /* chaced: name plus trailig shlash (for compares) */ int lenTagID; /* cached length of tag ID, for performance reasons */ } instanceData; typedef struct configSettings_s { uchar *pszTagName; /**< name of tag start value that indicates snmptrapd initiated message */ } configSettings_t; configSettings_t cs; //TODO: enable for v6 #if 0 SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */ BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars cs.pszTagName = NULL; resetConfigVariables(NULL, NULL); ENDinitConfVars #endif BEGINcreateInstance CODESTARTcreateInstance ENDcreateInstance BEGINisCompatibleWithFeature CODESTARTisCompatibleWithFeature ENDisCompatibleWithFeature BEGINfreeInstance CODESTARTfreeInstance free(pData->pszTagName); free(pData->pszTagID); ENDfreeInstance BEGINdbgPrintInstInfo CODESTARTdbgPrintInstInfo dbgprintf("mmsnmptrapd\n"); ENDdbgPrintInstInfo BEGINtryResume CODESTARTtryResume ENDtryResume /* get string up to the next SP or '/'. Stops at max size. * dst, lenDst (receive buffer) must be given. lenDst is * max length on entry and actual length on exit. */ static int getTagComponent(uchar *tag, uchar *dst, int *lenDst) { int end = *lenDst - 1; /* -1 for NUL-char! */ int i; i = 0; dbgprintf("XXXX: getTagComponent tag on input: '%s'(%p)\n", tag, tag); if(tag[i] != '/') goto done; ++tag; while(i < end && tag[i] != '\0' && tag[i] != ' ' && tag[i] != '/') { dst[i] = tag[i]; ++i; } dst[i] = '\0'; dbgprintf("XXXX: getTagComponent dst on output: '%s', len %d\n", dst, i); *lenDst = i; done: return i; } BEGINdoAction int lenTAG; int lenSever; int lenHost; msg_t *pMsg; uchar *pszTag; uchar pszSever[512]; uchar pszHost[512]; CODESTARTdoAction pMsg = (msg_t*) ppString[0]; dbgprintf("XXXX: mmsnmptrapd called with pMsg %p\n", pMsg); getTAG(pMsg, &pszTag, &lenTAG); if(strncmp((char*)pszTag, (char*)pData->pszTagID, pData->lenTagID)) { DBGPRINTF("tag '%s' not matching, mmsnmptrapd ignoring this message\n", pszTag); FINALIZE; } lenSever = sizeof(pszSever); dbgprintf("XXXX: pszTag: '%s', lenID %d\n", pszTag, pData->lenTagID); getTagComponent(pszTag+pData->lenTagID-1, pszSever, &lenSever); lenHost = sizeof(pszHost); getTagComponent(pszTag+pData->lenTagID+lenSever, pszHost, &lenHost); dbgprintf("XXXX: mmsnmptrapd sever '%s'(%d), host '%s'(%d)\n", pszSever, lenSever, pszHost,lenHost); if(pszHost[lenHost-1] == ':') { pszHost[lenHost-1] = '\0'; --lenHost; } /* now apply new settings */ MsgSetTAG(pMsg, pData->pszTagName, pData->lenTagID); MsgSetHOSTNAME(pMsg, pszHost, lenHost); finalize_it: ENDdoAction BEGINparseSelectorAct CODESTARTparseSelectorAct CODE_STD_STRING_REQUESTparseSelectorAct(1) /* first check if this config line is actually for us */ if(strncmp((char*) p, ":mmsnmptrapd:", sizeof(":mmsnmptrapd:") - 1)) { ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED); } /* ok, if we reach this point, we have something for us */ p += sizeof(":mmsnmptrapd:") - 1; /* eat indicator sequence (-1 because of '\0'!) */ CHKiRet(createInstance(&pData)); /* check if a non-standard template is to be applied */ if(*(p-1) == ';') --p; /* we call the function below because we need to call it via our interface definition. However, * the format specified (if any) is always ignored. */ CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_TPL_AS_MSG, (uchar*) "RSYSLOG_FileFormat")); /* finally build the instance */ if(cs.pszTagName == NULL) { pData->pszTagName = (uchar*) strdup("snmptrapd:"); pData->pszTagID = (uchar*) strdup("snmptrapd/"); } else { int lenTag = ustrlen(cs.pszTagName); /* new tag value (with colon at the end) */ CHKmalloc(pData->pszTagName = MALLOC(lenTag + 2)); memcpy(pData->pszTagName, cs.pszTagName, lenTag); memcpy(pData->pszTagName+lenTag, ":", 2); /* tag ID for comparisions */ CHKmalloc(pData->pszTagID = MALLOC(lenTag + 2)); memcpy(pData->pszTagID, cs.pszTagName, lenTag); memcpy(pData->pszTagID+lenTag, "/", 2); free(cs.pszTagName); /* no longer needed */ } pData->lenTagID = ustrlen(pData->pszTagID); /* all config vars auto-reset! */ cs.pszTagName = NULL; CODE_STD_FINALIZERparseSelectorAct ENDparseSelectorAct BEGINmodExit CODESTARTmodExit 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; free(cs.pszTagName); cs.pszTagName = NULL; RETiRet; } BEGINmodInit() rsRetVal localRet; rsRetVal (*pomsrGetSupportedTplOpts)(unsigned long *pOpts); unsigned long opts; int bMsgPassingSupported; CODESTARTmodInit //TODO v6: add SCOPINGmodInit *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ CODEmodInit_QueryRegCFSLineHdlr /* check if the rsyslog core supports parameter passing code */ bMsgPassingSupported = 0; localRet = pHostQueryEtryPt((uchar*)"OMSRgetSupportedTplOpts", &pomsrGetSupportedTplOpts); if(localRet == RS_RET_OK) { /* found entry point, so let's see if core supports msg passing */ CHKiRet((*pomsrGetSupportedTplOpts)(&opts)); if(opts & OMSR_TPL_AS_MSG) bMsgPassingSupported = 1; } else if(localRet != RS_RET_ENTRY_POINT_NOT_FOUND) { ABORT_FINALIZE(localRet); /* Something else went wrong, not acceptable */ } if(!bMsgPassingSupported) { DBGPRINTF("mmsnmptrapd: msg-passing is not supported by rsyslog core, " "can not continue.\n"); ABORT_FINALIZE(RS_RET_NO_MSG_PASSING); } CHKiRet(objUse(errmsg, CORE_COMPONENT)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"mmsnmptrapdtag", 0, eCmdHdlrInt, NULL, &cs.pszTagName, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID)); ENDmodInit /* vi:set ai: */