diff options
author | Rainer Gerhards <rgerhards@adiscon.com> | 2013-09-26 12:41:50 +0200 |
---|---|---|
committer | Rainer Gerhards <rgerhards@adiscon.com> | 2013-09-26 12:41:50 +0200 |
commit | a8b1e96d7bf91d97646789c1805587ca1ebba3e9 (patch) | |
tree | fea136da0c5c290c953d8b80a4b233a96de5d247 | |
parent | 039e23df84ed435ebd674ff5bcad6098b5038664 (diff) | |
parent | b810f0dd3ade85efeb7dc9b99fade798764d0ac2 (diff) | |
download | rsyslog-a8b1e96d7bf91d97646789c1805587ca1ebba3e9.tar.gz rsyslog-a8b1e96d7bf91d97646789c1805587ca1ebba3e9.tar.bz2 rsyslog-a8b1e96d7bf91d97646789c1805587ca1ebba3e9.zip |
Merge branch 'v7-stable-mmrfc5424addhmac'
Conflicts:
Makefile.am
configure.ac
runtime/msg.c
runtime/rsyslog.h
-rw-r--r-- | Makefile.am | 4 | ||||
-rw-r--r-- | configure.ac | 15 | ||||
-rw-r--r-- | plugins/mmpstrucdata/Makefile.am | 8 | ||||
-rw-r--r-- | plugins/mmpstrucdata/mmpstrucdata.c | 400 | ||||
-rw-r--r-- | plugins/mmrfc5424addhmac/mmrfc5424addhmac.c | 266 | ||||
-rw-r--r-- | plugins/pmlastmsg/pmlastmsg.c | 2 | ||||
-rw-r--r-- | plugins/pmrfc3164sd/pmrfc3164sd.c | 2 | ||||
-rw-r--r-- | runtime/msg.c | 92 | ||||
-rw-r--r-- | runtime/msg.h | 21 | ||||
-rw-r--r-- | runtime/rsyslog.h | 2 | ||||
-rw-r--r-- | tools/pmrfc3164.c | 2 | ||||
-rw-r--r-- | tools/pmrfc5424.c | 2 |
12 files changed, 663 insertions, 153 deletions
diff --git a/Makefile.am b/Makefile.am index 3923ca90..c5e41c75 100644 --- a/Makefile.am +++ b/Makefile.am @@ -253,6 +253,10 @@ if ENABLE_MMFIELDS SUBDIRS += plugins/mmfields endif +if ENABLE_MMPSTRUCDATA +SUBDIRS += plugins/mmpstrucdata +endif + if ENABLE_MMRFC5424ADDHMAC SUBDIRS += plugins/mmrfc5424addhmac endif diff --git a/configure.ac b/configure.ac index 324a680d..e136abd6 100644 --- a/configure.ac +++ b/configure.ac @@ -1002,6 +1002,19 @@ AC_ARG_ENABLE(mmfields, ) AM_CONDITIONAL(ENABLE_MMFIELDS, test x$enable_mmfields = xyes) +# mmpstrucdata +AC_ARG_ENABLE(mmpstrucdata, + [AS_HELP_STRING([--enable-mmpstrucdata],[Enable building mmpstrucdata support @<:@default=no@:>@])], + [case "${enableval}" in + yes) enable_mmpstrucdata="yes" ;; + no) enable_mmpstrucdata="no" ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-mmpstrucdata) ;; + esac], + [enable_mmpstrucdata=no] +) +AM_CONDITIONAL(ENABLE_MMPSTRUCDATA, test x$enable_mmpstrucdata = xyes) + + # mmrfc5424addhmac AC_ARG_ENABLE(mmrfc5424addhmac, [AS_HELP_STRING([--enable-mmrfc5424addhmac],[Enable building mmrfc5424addhmac support @<:@default=no@:>@])], @@ -1540,6 +1553,7 @@ AC_CONFIG_FILES([Makefile \ plugins/mmutf8fix/Makefile \ plugins/mmcount/Makefile \ plugins/mmfields/Makefile \ + plugins/mmpstrucdata/Makefile \ plugins/mmrfc5424addhmac/Makefile \ plugins/omelasticsearch/Makefile \ plugins/sm_cust_bindcdr/Makefile \ @@ -1606,6 +1620,7 @@ echo " mmjaduit module will be compiled: $enable_mmaudit" echo " mmsnmptrapd module will be compiled: $enable_mmsnmptrapd" echo " mmutf8fix enabled: $enable_mmutf8fix" echo " mmrfc5424addhmac enabled: $enable_mmrfc5424addhmac" +echo " mmpstrucdata enabled: $enable_mmpstrucdata" echo echo "---{ strgen modules }---" echo " sm_cust_bindcdr module will be compiled: $enable_sm_cust_bindcdr" diff --git a/plugins/mmpstrucdata/Makefile.am b/plugins/mmpstrucdata/Makefile.am new file mode 100644 index 00000000..090150ab --- /dev/null +++ b/plugins/mmpstrucdata/Makefile.am @@ -0,0 +1,8 @@ +pkglib_LTLIBRARIES = mmpstrucdata.la + +mmpstrucdata_la_SOURCES = mmpstrucdata.c +mmpstrucdata_la_CPPFLAGS = $(RSRT_CFLAGS) $(PTHREADS_CFLAGS) +mmpstrucdata_la_LDFLAGS = -module -avoid-version +mmpstrucdata_la_LIBADD = + +EXTRA_DIST = diff --git a/plugins/mmpstrucdata/mmpstrucdata.c b/plugins/mmpstrucdata/mmpstrucdata.c new file mode 100644 index 00000000..4b2a985b --- /dev/null +++ b/plugins/mmpstrucdata/mmpstrucdata.c @@ -0,0 +1,400 @@ +/* mmpstrucdata.c + * Parse all fields of the message into structured data inside the + * JSON tree. + * + * Copyright 2013 Adiscon GmbH. + * + * This file is part of rsyslog. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * -or- + * see COPYING.ASL20 in the source distribution + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "config.h" +#include "rsyslog.h" +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <signal.h> +#include <errno.h> +#include <unistd.h> +#include <stdint.h> +#include "conf.h" +#include "syslogd-types.h" +#include "srUtils.h" +#include "template.h" +#include "module-template.h" +#include "errmsg.h" + +MODULE_TYPE_OUTPUT +MODULE_TYPE_NOKEEP +MODULE_CNFNAME("mmpstrucdata") + + +DEFobjCurrIf(errmsg); +DEF_OMOD_STATIC_DATA + +/* config variables */ + +typedef struct _instanceData { + uchar *jsonRoot; /**< container where to store fields */ +} instanceData; + +struct modConfData_s { + rsconf_t *pConf; /* our overall config object */ +}; +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 exec process */ + + +/* tables for interfacing with the v6 config system */ +/* action (instance) parameters */ +static struct cnfparamdescr actpdescr[] = { + { "jsonroot", eCmdHdlrString, 0 } +}; +static struct cnfparamblk actpblk = + { CNFPARAMBLK_VERSION, + sizeof(actpdescr)/sizeof(struct cnfparamdescr), + actpdescr + }; + +BEGINbeginCnfLoad +CODESTARTbeginCnfLoad + loadModConf = pModConf; + pModConf->pConf = pConf; +ENDbeginCnfLoad + +BEGINendCnfLoad +CODESTARTendCnfLoad +ENDendCnfLoad + +BEGINcheckCnf +CODESTARTcheckCnf +ENDcheckCnf + +BEGINactivateCnf +CODESTARTactivateCnf + runModConf = pModConf; +ENDactivateCnf + +BEGINfreeCnf +CODESTARTfreeCnf +ENDfreeCnf + + +BEGINcreateInstance +CODESTARTcreateInstance +ENDcreateInstance + + +BEGINisCompatibleWithFeature +CODESTARTisCompatibleWithFeature +ENDisCompatibleWithFeature + + +BEGINfreeInstance +CODESTARTfreeInstance + free(pData->jsonRoot); +ENDfreeInstance + + +static inline void +setInstParamDefaults(instanceData *pData) +{ + pData->jsonRoot = NULL; +} + +BEGINnewActInst + struct cnfparamvals *pvals; + int i; +CODESTARTnewActInst + DBGPRINTF("newActInst (mmpstrucdata)\n"); + if((pvals = nvlstGetParams(lst, &actpblk, NULL)) == NULL) { + ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); + } + + CODE_STD_STRING_REQUESTnewActInst(1) + CHKiRet(OMSRsetEntry(*ppOMSR, 0, NULL, OMSR_TPL_AS_MSG)); + CHKiRet(createInstance(&pData)); + setInstParamDefaults(pData); + + for(i = 0 ; i < actpblk.nParams ; ++i) { + if(!pvals[i].bUsed) + continue; + if(!strcmp(actpblk.descr[i].name, "jsonroot")) { + pData->jsonRoot = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else { + dbgprintf("mmpstrucdata: program error, non-handled " + "param '%s'\n", actpblk.descr[i].name); + } + } + if(pData->jsonRoot == NULL) { + CHKmalloc(pData->jsonRoot = (uchar*) strdup("!")); + } + +CODE_STD_FINALIZERnewActInst + cnfparamvalsDestruct(pvals, &actpblk); +ENDnewActInst + + +BEGINdbgPrintInstInfo +CODESTARTdbgPrintInstInfo +ENDdbgPrintInstInfo + + +BEGINtryResume +CODESTARTtryResume +ENDtryResume + + +static inline rsRetVal +parsePARAM_VALUE(uchar *sdbuf, int lenbuf, int *curridx, uchar *fieldbuf) +{ + int i, j; + DEFiRet; +dbgprintf("DDDD: parsePARAM_VALUE\n"); + i = *curridx; + j = 0; + while(i < lenbuf && sdbuf[i] != '"') { + if(sdbuf[i] == '\\') { + if(++i == lenbuf) { + fieldbuf[j++] = '\\'; + } else { + if(sdbuf[i] == '"') { + fieldbuf[j++] = '"'; + } else if(sdbuf[i] == '\\') { + fieldbuf[j++] = '\\'; + } else if(sdbuf[i] == ']') { + fieldbuf[j++] = '"'; + } else { + fieldbuf[j++] = '\\'; + fieldbuf[j++] = sdbuf[i]; + } + ++i; + } + } else { + fieldbuf[j++] = sdbuf[i++]; + } + } + fieldbuf[j] = '\0'; + *curridx = i; +dbgprintf("DDDD: parsePARAM_VALUE: '%s'\n", fieldbuf); + RETiRet; +} + + +static rsRetVal +parseSD_NAME(uchar *sdbuf, int lenbuf, int *curridx, uchar *namebuf) +{ + int i, j; + DEFiRet; +dbgprintf("DDDD: parseSD_NAME %s\n", sdbuf+*curridx); + i = *curridx; + for(j = 0 ; i < lenbuf && j < 32; ++j) { + if( sdbuf[i] == '=' || sdbuf[i] == '"' + || sdbuf[i] == ']' || sdbuf[i] == ' ') + break; + namebuf[j] = sdbuf[i++]; + } + namebuf[j] = '\0'; +dbgprintf("DDDD: parseSD_NAME, NAME: '%s'\n", namebuf); + *curridx = i; + RETiRet; +} + + +static inline rsRetVal +parseSD_PARAM(instanceData *pData, uchar *sdbuf, int lenbuf, int *curridx, struct json_object *jroot) +{ + int i; + uchar pName[33]; + uchar pVal[32*1024]; + struct json_object *jval; + DEFiRet; +dbgprintf("DDDD: parseSD_PARAM %s\n", sdbuf+*curridx); + + i = *curridx; + CHKiRet(parseSD_NAME(sdbuf, lenbuf, &i, pName)); + if(sdbuf[i] != '=') { + ABORT_FINALIZE(RS_RET_STRUC_DATA_INVLD); + } + ++i; + if(sdbuf[i] != '"') { + ABORT_FINALIZE(RS_RET_STRUC_DATA_INVLD); + } + ++i; + CHKiRet(parsePARAM_VALUE(sdbuf, lenbuf, &i, pVal)); + if(sdbuf[i] != '"') { + ABORT_FINALIZE(RS_RET_STRUC_DATA_INVLD); + } + ++i; + + jval = json_object_new_string((char*)pVal); + json_object_object_add(jroot, (char*)pName, jval); + + *curridx = i; +finalize_it: + RETiRet; +} + + +static inline rsRetVal +parseSD_ELEMENT(instanceData *pData, uchar *sdbuf, int lenbuf, int *curridx, struct json_object *jroot) +{ + int i; + uchar sd_id[33]; + struct json_object *json; + DEFiRet; +dbgprintf("DDDD: parseSD_ELEMENT: %s\n", sdbuf+*curridx); + + i = *curridx; + if(sdbuf[i] != '[') { + ABORT_FINALIZE(RS_RET_STRUC_DATA_INVLD); + } + ++i; /* eat '[' */ + + CHKiRet(parseSD_NAME(sdbuf, lenbuf, &i, sd_id)); + json = json_object_new_object(); + + while(i < lenbuf) { + if(sdbuf[i] == ']') { + break; + } else if(sdbuf[i] != ' ') { + ABORT_FINALIZE(RS_RET_STRUC_DATA_INVLD); + } + ++i; + while(i < lenbuf && sdbuf[i] == ' ') + ++i; + CHKiRet(parseSD_PARAM(pData, sdbuf, lenbuf, &i, json)); +dbgprintf("DDDD: done parseSD_PARAM, in loop, i:%d, lenbuf:%d, rest: %s\n", i, lenbuf, sdbuf+i); + } + + if(sdbuf[i] != ']') { + DBGPRINTF("mmpstrucdata: SD-ELEMENT does not terminate with " + "']': '%s'\n", sdbuf+i); + ABORT_FINALIZE(RS_RET_STRUC_DATA_INVLD); + } + ++i; /* eat ']' */ + *curridx = i; + json_object_object_add(jroot, (char*)sd_id, json); +dbgprintf("DDDD: SD_ELEMENT: json: '%s'\n", json_object_get_string(json)); +dbgprintf("DDDD: SD_ELEMENT: jroot '%s'\n", json_object_get_string(json)); +finalize_it: +dbgprintf("DDDD: parseSD_ELEMENT iRet:%d, i:%d, *curridx:%d\n", iRet, i, *curridx); + RETiRet; +} + +static inline rsRetVal +parse_sd(instanceData *pData, msg_t *pMsg) +{ +#if 0 + uchar fieldbuf[32*1024]; + uchar fieldname[512]; + struct json_object *json; + struct json_object *jval; + int field; + uchar *buf; +#endif + struct json_object *json, *jroot; + uchar *sdbuf; + int lenbuf; + int i = 0; + DEFiRet; + +#if 0 + if(lenMsg < (int) sizeof(fieldbuf)) { + buf = fieldbuf; + } else { + CHKmalloc(buf = malloc(lenMsg+1)); + } +#endif + +dbgprintf("DDDD: parse_sd\n"); + json = json_object_new_object(); + if(json == NULL) { + ABORT_FINALIZE(RS_RET_ERR); + } + MsgGetStructuredData(pMsg, &sdbuf,&lenbuf); + while(i < lenbuf) { + CHKiRet(parseSD_ELEMENT(pData, sdbuf, lenbuf, &i, json)); +dbgprintf("DDDD: parse_sd, i:%d\n", i); + } +dbgprintf("DDDD: json: '%s'\n", json_object_get_string(json)); + + jroot = json_object_new_object(); + if(jroot == NULL) { + ABORT_FINALIZE(RS_RET_ERR); + } + json_object_object_add(jroot, "RFC5424-SD", json); + msgAddJSON(pMsg, pData->jsonRoot, jroot); +finalize_it: + RETiRet; +} + + +BEGINdoAction + msg_t *pMsg; +CODESTARTdoAction +dbgprintf("DDDD: enter mmpstrucdata\n"); + pMsg = (msg_t*) ppString[0]; + if(!MsgHasStructuredData(pMsg)) { + DBGPRINTF("mmpstrucdata: message does not have structured data\n"); + FINALIZE; + } +dbgprintf("DDDD: parse mmpstrucdata\n"); + /* don't check return code - we never want rsyslog to retry + * or suspend this action! + */ + parse_sd(pData, pMsg); +dbgprintf("DDDD: done parse mmpstrucdata\n"); +finalize_it: +ENDdoAction + + +BEGINparseSelectorAct +CODESTARTparseSelectorAct +CODE_STD_STRING_REQUESTparseSelectorAct(1) + if(strncmp((char*) p, ":mmpstrucdata:", sizeof(":mmpstrucdata:") - 1)) { + errmsg.LogError(0, RS_RET_LEGA_ACT_NOT_SUPPORTED, + "mmpstrucdata supports only v6+ config format, use: " + "action(type=\"mmpstrucdata\" ...)"); + } + ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED); +CODE_STD_FINALIZERparseSelectorAct +ENDparseSelectorAct + + +BEGINmodExit +CODESTARTmodExit + objRelease(errmsg, CORE_COMPONENT); +ENDmodExit + + +BEGINqueryEtryPt +CODESTARTqueryEtryPt +CODEqueryEtryPt_STD_OMOD_QUERIES +CODEqueryEtryPt_STD_CONF2_OMOD_QUERIES +CODEqueryEtryPt_STD_CONF2_QUERIES +ENDqueryEtryPt + + + +BEGINmodInit() +CODESTARTmodInit + *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ +CODEmodInit_QueryRegCFSLineHdlr + DBGPRINTF("mmpstrucdata: module compiled with rsyslog version %s.\n", VERSION); + CHKiRet(objUse(errmsg, CORE_COMPONENT)); +ENDmodInit diff --git a/plugins/mmrfc5424addhmac/mmrfc5424addhmac.c b/plugins/mmrfc5424addhmac/mmrfc5424addhmac.c index e5ada8e0..6adad187 100644 --- a/plugins/mmrfc5424addhmac/mmrfc5424addhmac.c +++ b/plugins/mmrfc5424addhmac/mmrfc5424addhmac.c @@ -1,6 +1,30 @@ /* mmrfc5424addhmac.c * custom module: add hmac to RFC5424 messages * + * Note on important design decision: This module is fully self-contained. + * Most importantly, it does not rely on mmpstrucdata to populate the + * structured data portion of the messages JSON. There are two reasons + * for this: + * 1. robustness + * - this guard against misconfiguration + * - it permits us to be more liberal in regard to malformed + * structured data + * - it permits us to handle border-cases (like duplicate + * SD-IDs) with much less complexity + * 2. performance + * With being "on the spot" of what we need we can reduce memory + * reads and writes. This is a considerable save if the JSON representation + * is not otherwise needed. + * + * Note that the recommended calling sequence if both of these modules + * are used is + * + * 1. mmrfc5424addhmac + * 2. mmpstrucdata + * + * This sequence permits mmpstrucdata to pick up the modifications we + * made in this module here. + * * Copyright 2013 Adiscon GmbH. * * This file is part of rsyslog. @@ -30,6 +54,7 @@ #include <errno.h> #include <unistd.h> #include <stdint.h> +#include <openssl/hmac.h> #include "conf.h" #include "syslogd-types.h" #include "srUtils.h" @@ -48,6 +73,11 @@ DEF_OMOD_STATIC_DATA /* config variables */ typedef struct _instanceData { + uchar *key; + int16_t keylen; /* cached length of key, to avoid recomputation */ + uchar *sdid; /* SD-ID to be used to persist the hmac */ + int16_t sdidLen; + const EVP_MD *algo; } instanceData; struct modConfData_s { @@ -60,9 +90,9 @@ static modConfData_t *runModConf = NULL;/* modConf ptr to use for the current ex /* tables for interfacing with the v6 config system */ /* action (instance) parameters */ static struct cnfparamdescr actpdescr[] = { - { "mode", eCmdHdlrGetWord, 0 }, - { "replacementchar", eCmdHdlrGetChar, 0 }, - { "ipv4.bits", eCmdHdlrInt, 0 }, + { "key", eCmdHdlrString, 1 }, + { "hashfunction", eCmdHdlrString, 1 }, + { "sd_id", eCmdHdlrGetWord, 1 } }; static struct cnfparamblk actpblk = { CNFPARAMBLK_VERSION, @@ -112,11 +142,12 @@ ENDfreeInstance static inline void setInstParamDefaults(instanceData *pData) { - //pData->replChar = 'x'; + pData->key = NULL; } BEGINnewActInst struct cnfparamvals *pvals; + char *ciphername; int i; CODESTARTnewActInst DBGPRINTF("newActInst (mmrfc5424addhmac)\n"); @@ -133,9 +164,22 @@ CODESTARTnewActInst if(!pvals[i].bUsed) continue; if(!strcmp(actpblk.descr[i].name, "replacementchar")) { - // pData->replChar = es_getBufAddr(pvals[i].val.d.estr)[0]; - } else if(!strcmp(actpblk.descr[i].name, "ipv4.bits")) { - // pData->ipv4.bits = (int8_t) pvals[i].val.d.n; + pData->key = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + pData->keylen = es_strlen(pvals[i].val.d.estr); + } else if(!strcmp(actpblk.descr[i].name, "hashfunction")) { + ciphername = es_str2cstr(pvals[i].val.d.estr, NULL); + pData->algo = EVP_get_digestbyname(ciphername); + if(pData->algo == NULL) { + errmsg.LogError(0, RS_RET_CRY_INVLD_ALGO, + "hashFunction '%s' unknown to openssl - " + "cannot continue", ciphername); + free(ciphername); + ABORT_FINALIZE(RS_RET_CRY_INVLD_ALGO); + } + free(ciphername); + } else if(!strcmp(actpblk.descr[i].name, "sd_id")) { + pData->sdid = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + pData->sdidLen = es_strlen(pvals[i].val.d.estr); } else { dbgprintf("mmrfc5424addhmac: program error, non-handled " "param '%s'\n", actpblk.descr[i].name); @@ -157,122 +201,138 @@ CODESTARTtryResume ENDtryResume -#if 0 -/* write an IP address octet to the output position */ -static int -writeOctet(uchar *msg, int idx, int *nxtidx, uint8_t octet) +/* turn the binary data in bin of length len into a + * printable hex string. "print" must be 2*len+1 (for \0) + */ +static inline void +hexify(uchar *bin, int len, uchar *print) { - if(octet > 99) { - msg[idx++] = '0' + octet / 100; - octet = octet % 100; - } - if(octet > 9) { - msg[idx++] = '0' + octet / 10; - octet = octet % 10; + static const char hexchars[16] = + {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; + int iSrc, iDst; + + for(iSrc = iDst = 0 ; iSrc < len ; ++iSrc) { + print[iDst++] = hexchars[bin[iSrc]>>4]; + print[iDst++] = hexchars[bin[iSrc]&0x0f]; } - msg[idx++] = '0' + octet; + print[iDst] = '\0'; +} - if(nxtidx != NULL) { - if(idx + 1 != *nxtidx) { - /* we got shorter, fix it! */ - msg[idx] = '.'; - *nxtidx = idx + 1; + +/* skip to end of current SD-ID. This function can be improved + * in regard to fully parsing based on RFC5424, HOWEVER, this would + * also reduce performance. So we consider the current implementation + * to be superior. + */ +static inline void +skipSDID(uchar *sdbuf, int sdlen, int *rootIdx) +{ + int i; + i = *rootIdx; + while(i < sdlen) { + if(sdbuf[i] == ']') { + if(i > *rootIdx && sdbuf[i-1] == '\\') { + ; /* escaped, nothing to do! */ + } else { + ++i; /* eat ']' */ + break; + } } + ++i; } - return idx; + *rootIdx = i; } -/* currently works for IPv4 only! */ -void -anonip(instanceData *pData, uchar *msg, int *pLenMsg, int *idx) +static inline void +getSDID(uchar *sdbuf, int sdlen, int *rootIdx, uchar *sdid) { - int i = *idx; - int octet; - uint32_t ipv4addr; - int ipstart[4]; - int j; - int endpos; - int lenMsg = *pLenMsg; - - while(i < lenMsg && (msg[i] <= '0' || msg[i] >= '9')) { - ++i; /* skip to first number */ - } - if(i >= lenMsg) + int i, j; + i = *rootIdx; + j = 0; + + if(sdbuf[i] != '[') { + ++i; goto done; + } - /* got digit, let's see if ip */ - ipstart[0] = i; - octet = getnum(msg, lenMsg, &i); - if(octet > 255 || msg[i] != '.') goto done; - ipv4addr = octet << 24; - ++i; - ipstart[1] = i; - octet = getnum(msg, lenMsg, &i); - if(octet > 255 || msg[i] != '.') goto done; - ipv4addr |= octet << 16; ++i; - ipstart[2] = i; - octet = getnum(msg, lenMsg, &i); - if(octet > 255 || msg[i] != '.') goto done; - ipv4addr |= octet << 8; - ++i; - ipstart[3] = i; - octet = getnum(msg, lenMsg, &i); - if(octet > 255 || !(msg[i] == ' ' || msg[i] == ':')) goto done; - ipv4addr |= octet; - - /* OK, we now found an ip address */ - if(pData->mode == SIMPLE_MODE) { - if(pData->ipv4.bits == 8) - j = ipstart[3]; - else if(pData->ipv4.bits == 16) - j = ipstart[2]; - else if(pData->ipv4.bits == 24) - j = ipstart[1]; - else /* due to our checks, this *must* be 32 */ - j = ipstart[0]; - while(j < i) { - if(msg[j] != '.') - msg[j] = pData->replChar; - ++j; - } - } else { /* REWRITE_MODE */ - ipv4addr &= ipv4masks[pData->ipv4.bits]; - if(pData->ipv4.bits > 24) - writeOctet(msg, ipstart[0], &(ipstart[1]), ipv4addr >> 24); - if(pData->ipv4.bits > 16) - writeOctet(msg, ipstart[1], &(ipstart[2]), (ipv4addr >> 16) & 0xff); - if(pData->ipv4.bits > 8) - writeOctet(msg, ipstart[2], &(ipstart[3]), (ipv4addr >> 8) & 0xff); - endpos = writeOctet(msg, ipstart[3], NULL, ipv4addr & 0xff); - /* if we had truncation, we need to shrink the msg */ - dbgprintf("existing i %d, endpos %d\n", i, endpos); - if(i - endpos > 0) { - *pLenMsg = lenMsg - (i - endpos); - memmove(msg+endpos, msg+i, lenMsg - i + 1); + while(i < sdlen && sdbuf[i] != '=' && sdbuf[i] != ' ' + && sdbuf[i] != ']' && sdbuf[i] != '"') { + sdid[j++] = sdbuf[i++]; + } +done: + sdid[j] = '\0'; + *rootIdx = i; +} + +/* check if "our" hmac is already present */ +static inline sbool +isHmacPresent(instanceData *pData, msg_t *pMsg) +{ + uchar *sdbuf; + rs_size_t sdlen; + sbool found; + int i; + uchar sdid[33]; /* RFC-based size limit */ + + MsgGetStructuredData(pMsg, &sdbuf, &sdlen); + + found = 0; + i = 0; + while(i < sdlen && !found) { + getSDID(sdbuf, sdlen, &i, sdid); + if(!strcmp((char*)pData->sdid, (char*)sdid)) { + found = 1; + break; } + skipSDID(sdbuf, sdlen, &i); } -done: *idx = i; - return; + return found; +} + +static inline rsRetVal +hashMsg(instanceData *pData, msg_t *pMsg) +{ + uchar *pRawMsg; + int lenRawMsg; + uchar *sdbuf; + rs_size_t sdlen; + unsigned int hashlen; + uchar hash[EVP_MAX_MD_SIZE]; + uchar hashPrintable[2*EVP_MAX_MD_SIZE+1]; + uchar newsd[64*1024]; /* we assume this is sufficient... */ + int lenNewsd; + DEFiRet; + + MsgGetStructuredData(pMsg, &sdbuf, &sdlen); + getRawMsg(pMsg, &pRawMsg, &lenRawMsg); + HMAC(pData->algo, pData->key, pData->keylen, + pRawMsg, lenRawMsg, hash, &hashlen); + hexify(hash, hashlen, hashPrintable); + lenNewsd = snprintf((char*)newsd, sizeof(newsd), "[%s hash=\"%s\"]", + (char*)pData->sdid, (char*)hashPrintable); + MsgAddToStructuredData(pMsg, newsd, lenNewsd); + RETiRet; } -#endif BEGINdoAction msg_t *pMsg; - uchar *msg; - int lenMsg; - int i; CODESTARTdoAction pMsg = (msg_t*) ppString[0]; - lenMsg = getMSGLen(pMsg); - msg = getMSG(pMsg); - for(i = 0 ; i < lenMsg ; ++i) { - anonip(pData, msg, &lenMsg, &i); + if( msgGetProtocolVersion(pMsg) == MSG_RFC5424_PROTOCOL + && !isHmacPresent(pData, pMsg)) { + hashMsg(pData, pMsg); + } else { + if(Debug) { + uchar *pRawMsg; + int lenRawMsg; + getRawMsg(pMsg, &pRawMsg, &lenRawMsg); + dbgprintf("mmrfc5424addhmac: non-rfc5424 or HMAC already " + "present: %.256s\n", pRawMsg); + } } - if(lenMsg != getMSGLen(pMsg)) - setMSGLen(pMsg, lenMsg); ENDdoAction @@ -292,6 +352,7 @@ ENDparseSelectorAct BEGINmodExit CODESTARTmodExit objRelease(errmsg, CORE_COMPONENT); + EVP_cleanup(); ENDmodExit @@ -306,8 +367,9 @@ ENDqueryEtryPt BEGINmodInit() CODESTARTmodInit - *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ + *ipIFVersProvided = CURR_MOD_IF_VERSION; CODEmodInit_QueryRegCFSLineHdlr DBGPRINTF("mmrfc5424addhmac: module compiled with rsyslog version %s.\n", VERSION); + OpenSSL_add_all_digests(); CHKiRet(objUse(errmsg, CORE_COMPONENT)); ENDmodInit diff --git a/plugins/pmlastmsg/pmlastmsg.c b/plugins/pmlastmsg/pmlastmsg.c index a290c446..8c475fbb 100644 --- a/plugins/pmlastmsg/pmlastmsg.c +++ b/plugins/pmlastmsg/pmlastmsg.c @@ -132,7 +132,7 @@ dbgprintf("wrong closing text!\n"); */ DBGPRINTF("pmlastmsg detected a \"last message repeated n times\" message\n"); - setProtocolVersion(pMsg, 0); + setProtocolVersion(pMsg, MSG_LEGACY_PROTOCOL); memcpy(&pMsg->tTIMESTAMP, &pMsg->tRcvdAt, sizeof(struct syslogTime)); MsgSetMSGoffs(pMsg, pMsg->offAfterPRI); /* we don't have a header! */ MsgSetTAG(pMsg, (uchar*)"", 0); diff --git a/plugins/pmrfc3164sd/pmrfc3164sd.c b/plugins/pmrfc3164sd/pmrfc3164sd.c index de5805bc..0ed4a56c 100644 --- a/plugins/pmrfc3164sd/pmrfc3164sd.c +++ b/plugins/pmrfc3164sd/pmrfc3164sd.c @@ -177,7 +177,7 @@ CODESTARTparse assert(pMsg->pszRawMsg != NULL); lenMsg = pMsg->iLenRawMsg - pMsg->offAfterPRI; /* note: offAfterPRI is already the number of PRI chars (do not add one!) */ p2parse = pMsg->pszRawMsg + pMsg->offAfterPRI; /* point to start of text, after PRI */ - setProtocolVersion(pMsg, 0); + setProtocolVersion(pMsg, MSG_LEGACY_PROTOCOL); /* Check to see if msg contains a timestamp. We start by assuming * that the message timestamp is the time of reception (which we diff --git a/runtime/msg.c b/runtime/msg.c index f3181898..2bd470a1 100644 --- a/runtime/msg.c +++ b/runtime/msg.c @@ -384,13 +384,6 @@ MsgSetRulesetByName(msg_t *pMsg, cstr_t *rulesetName) rulesetGetRuleset(runConf, &(pMsg->pRuleset), rsCStrGetSzStrNoNULL(rulesetName)); } - -static inline int getProtocolVersion(msg_t *pM) -{ - return(pM->iProtocolVersion); -} - - /* do a DNS reverse resolution, if not already done, reflect status * rgerhards, 2009-11-16 */ @@ -715,7 +708,7 @@ static inline rsRetVal msgBaseConstruct(msg_t **ppThis) pM->pszTIMESTAMP3339 = NULL; pM->pszTIMESTAMP_MySQL = NULL; pM->pszTIMESTAMP_PgSQL = NULL; - pM->pCSStrucData = NULL; + pM->pszStrucData = NULL; pM->pCSAPPNAME = NULL; pM->pCSPROCID = NULL; pM->pCSMSGID = NULL; @@ -859,10 +852,9 @@ CODESTARTobjDestruct(msg) free(pThis->pszRcvdAt_PgSQL); free(pThis->pszTIMESTAMP_MySQL); free(pThis->pszTIMESTAMP_PgSQL); + free(pThis->pszStrucData); if(pThis->iLenPROGNAME >= CONF_PROGNAME_BUFSIZE) free(pThis->PROGNAME.ptr); - if(pThis->pCSStrucData != NULL) - rsCStrDestruct(&pThis->pCSStrucData); if(pThis->pCSAPPNAME != NULL) rsCStrDestruct(&pThis->pCSAPPNAME); if(pThis->pCSPROCID != NULL) @@ -1014,8 +1006,13 @@ msg_t* MsgDup(msg_t* pOld) tmpCOPYSZ(HOSTNAME); } } + if(pOld->pszStrucData == NULL) { + pNew->pszStrucData = NULL; + } else { + pNew->pszStrucData = (uchar*)strdup((char*)pOld->pszStrucData); + pNew->lenStrucData = pOld->lenStrucData; + } - tmpCOPYCSTR(StrucData); tmpCOPYCSTR(APPNAME); tmpCOPYCSTR(PROCID); tmpCOPYCSTR(MSGID); @@ -1078,6 +1075,8 @@ static rsRetVal MsgSerialize(msg_t *pThis, strm_t *pStrm) CHKiRet(obj.SerializeProp(pStrm, UCHAR_CONSTANT("pszRcvFrom"), PROPTYPE_PSZ, (void*) psz)); psz = getRcvFromIP(pThis); CHKiRet(obj.SerializeProp(pStrm, UCHAR_CONSTANT("pszRcvFromIP"), PROPTYPE_PSZ, (void*) psz)); + psz = pThis->pszStrucData; + CHKiRet(obj.SerializeProp(pStrm, UCHAR_CONSTANT("pszRcvStrucData"), PROPTYPE_PSZ, (void*) psz)); if(pThis->json != NULL) { psz = (uchar*) json_object_get_string(pThis->json); CHKiRet(obj.SerializeProp(pStrm, UCHAR_CONSTANT("json"), PROPTYPE_PSZ, (void*) psz)); @@ -1087,7 +1086,6 @@ static rsRetVal MsgSerialize(msg_t *pThis, strm_t *pStrm) CHKiRet(obj.SerializeProp(pStrm, UCHAR_CONSTANT("localvars"), PROPTYPE_PSZ, (void*) psz)); } - objSerializePTR(pStrm, pCSStrucData, CSTR); objSerializePTR(pStrm, pCSAPPNAME, CSTR); objSerializePTR(pStrm, pCSPROCID, CSTR); objSerializePTR(pStrm, pCSMSGID, CSTR); @@ -1236,7 +1234,7 @@ MsgDeserialize(msg_t *pMsg, strm_t *pStrm) reinitVar(pVar); CHKiRet(objDeserializeProperty(pVar, pStrm)); } - if(isProp("pCSStrucData")) { + if(isProp("pszStrucData")) { MsgSetStructuredData(pMsg, (char*) rsCStrGetSzStrNoNULL(pVar->val.pStr)); reinitVar(pVar); CHKiRet(objDeserializeProperty(pVar, pStrm)); @@ -1326,7 +1324,7 @@ static rsRetVal aquirePROCIDFromTAG(msg_t *pM) if(pM->pCSPROCID != NULL) return RS_RET_OK; /* we are already done ;) */ - if(getProtocolVersion(pM) != 0) + if(msgGetProtocolVersion(pM) != 0) return RS_RET_OK; /* we can only emulate if we have legacy format */ pszTag = (uchar*) ((pM->iLenTAG < CONF_TAG_BUFSIZE) ? pM->TAG.szBuf : pM->TAG.pszTAG); @@ -2009,7 +2007,7 @@ static inline void tryEmulateTAG(msg_t *pM, sbool bLockMutex) return; /* done, no need to emulate */ } - if(getProtocolVersion(pM) == 1) { + if(msgGetProtocolVersion(pM) == 1) { if(!strcmp(getPROCID(pM, MUTEX_ALREADY_LOCKED), "-")) { /* no process ID, use APP-NAME only */ MsgSetTAG(pM, (uchar*) getAPPNAME(pM, MUTEX_ALREADY_LOCKED), getAPPNAMELen(pM, MUTEX_ALREADY_LOCKED)); @@ -2109,42 +2107,27 @@ rsRetVal MsgSetStructuredData(msg_t *pMsg, char* pszStrucData) { DEFiRet; ISOBJ_TYPE_assert(pMsg, msg); - if(pMsg->pCSStrucData == NULL) { - /* we need to obtain the object first */ - CHKiRet(rsCStrConstruct(&pMsg->pCSStrucData)); - } - /* if we reach this point, we have the object */ - iRet = rsCStrSetSzStr(pMsg->pCSStrucData, (uchar*) pszStrucData); - + free(pMsg->pszStrucData); + CHKmalloc(pMsg->pszStrucData = (uchar*)strdup(pszStrucData)); + pMsg->lenStrucData = strlen(pszStrucData); finalize_it: RETiRet; } -/* get the length of the "STRUCTURED-DATA" sz string - * rgerhards, 2005-11-24 - */ -#if 0 /* This method is currently not called, be we like to preserve it */ -static int getStructuredDataLen(msg_t *pM) -{ - return (pM->pCSStrucData == NULL) ? 1 : rsCStrLen(pM->pCSStrucData); -} -#endif - -/* get the "STRUCTURED-DATA" as sz string - * rgerhards, 2005-11-24 - */ -static inline char *getStructuredData(msg_t *pM) +/* get the "STRUCTURED-DATA" as sz string, including length */ +void +MsgGetStructuredData(msg_t *pM, uchar **pBuf, rs_size_t *len) { - uchar *pszRet; - MsgLock(pM); - if(pM->pCSStrucData == NULL) - pszRet = UCHAR_CONSTANT("-"); - else - pszRet = rsCStrGetSzStrNoNULL(pM->pCSStrucData); + if(pM->pszStrucData == NULL) { + *pBuf = UCHAR_CONSTANT("-"), + *len = 1; + } else { + *pBuf = pM->pszStrucData, + *len = pM->lenStrucData; + } MsgUnlock(pM); - return (char*) pszRet; } /* get the "programname" as sz string @@ -2179,7 +2162,7 @@ static void tryEmulateAPPNAME(msg_t *pM) if(pM->pCSAPPNAME != NULL) return; /* we are already done */ - if(getProtocolVersion(pM) == 0) { + if(msgGetProtocolVersion(pM) == 0) { /* only then it makes sense to emulate */ MsgSetAPPNAME(pM, (char*)getProgramName(pM, MUTEX_ALREADY_LOCKED)); } @@ -2965,7 +2948,7 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe, pRes = (uchar*)getProtocolVersionString(pMsg); break; case PROP_STRUCTURED_DATA: - pRes = (uchar*)getStructuredData(pMsg); + MsgGetStructuredData(pMsg, &pRes, &bufLen); break; case PROP_APP_NAME: pRes = (uchar*)getAPPNAME(pMsg, LOCK_MUTEX); @@ -3863,7 +3846,7 @@ rsRetVal MsgSetProperty(msg_t *pThis, var_t *pProp) prop.Destruct(&propRcvFrom); } else if(isProp("pszHOSTNAME")) { MsgSetHOSTNAME(pThis, rsCStrGetSzStrNoNULL(pProp->val.pStr), rsCStrLen(pProp->val.pStr)); - } else if(isProp("pCSStrucData")) { + } else if(isProp("pszStrucData")) { MsgSetStructuredData(pThis, (char*) rsCStrGetSzStrNoNULL(pProp->val.pStr)); } else if(isProp("pCSAPPNAME")) { MsgSetAPPNAME(pThis, (char*) rsCStrGetSzStrNoNULL(pProp->val.pStr)); @@ -4217,6 +4200,23 @@ finalize_it: RETiRet; } +rsRetVal +MsgAddToStructuredData(msg_t *pMsg, uchar *toadd, rs_size_t len) +{ + uchar *newptr; + rs_size_t newlen; + DEFiRet; + newlen = pMsg->lenStrucData + len; + CHKmalloc(newptr = (uchar*) realloc(pMsg->pszStrucData, newlen+1)); + pMsg->pszStrucData = newptr; + memcpy(pMsg->pszStrucData+pMsg->lenStrucData, toadd, len); + pMsg->pszStrucData[newlen] = '\0'; + pMsg->lenStrucData = newlen; +finalize_it: + RETiRet; +} + + /* dummy */ rsRetVal msgQueryInterface(void) { return RS_RET_NOT_IMPLEMENTED; } diff --git a/runtime/msg.h b/runtime/msg.h index 1d9e2c70..ed15622a 100644 --- a/runtime/msg.h +++ b/runtime/msg.h @@ -30,6 +30,7 @@ #include <pthread.h> #include <libestr.h> +#include <stdint.h> #include <json.h> #include "obj.h" #include "syslogd-types.h" @@ -85,7 +86,8 @@ struct msg { char *pszTIMESTAMP3339; /* TIMESTAMP as RFC3339 formatted string (32 charcters at most) */ char *pszTIMESTAMP_MySQL;/* TIMESTAMP as MySQL formatted string (always 14 charcters) */ char *pszTIMESTAMP_PgSQL;/* TIMESTAMP as PgSQL formatted string (always 21 characters) */ - cstr_t *pCSStrucData; /* STRUCTURED-DATA */ + uchar *pszStrucData; /* STRUCTURED-DATA */ + uint16_t lenStrucData; /* (cached) length of STRUCTURED-DATA */ cstr_t *pCSAPPNAME; /* APP-NAME */ cstr_t *pCSPROCID; /* PROCID */ cstr_t *pCSMSGID; /* MSGID */ @@ -143,6 +145,9 @@ struct msg { #define NEEDS_ACLCHK_U 0x080 /* check UDP ACLs after DNS resolution has been done in main queue consumer */ #define NO_PRI_IN_RAW 0x100 /* rawmsg does not include a PRI (Solaris!), but PRI is already set correctly in the msg object */ +/* (syslog) protocol types */ +#define MSG_LEGACY_PROTOCOL 0 +#define MSG_RFC5424_PROTOCOL 1 /* function prototypes */ @@ -165,6 +170,8 @@ void MsgSetTAG(msg_t *pMsg, uchar* pszBuf, size_t lenBuf); void MsgSetRuleset(msg_t *pMsg, ruleset_t*); rsRetVal MsgSetFlowControlType(msg_t *pMsg, flowControl_t eFlowCtl); rsRetVal MsgSetStructuredData(msg_t *pMsg, char* pszStrucData); +rsRetVal MsgAddToStructuredData(msg_t *pMsg, uchar *toadd, rs_size_t len); +void MsgGetStructuredData(msg_t *pM, uchar **pBuf, rs_size_t *len); rsRetVal msgSetFromSockinfo(msg_t *pThis, struct sockaddr_storage *sa); void MsgSetRcvFrom(msg_t *pMsg, prop_t*); void MsgSetRcvFromStr(msg_t *pMsg, uchar* pszRcvFrom, int, prop_t **); @@ -221,6 +228,18 @@ msgUnsetJSON(msg_t *pMsg, uchar *varname) { return msgDelJSON(pMsg, varname+1); } +static inline int +msgGetProtocolVersion(msg_t *pM) +{ + return(pM->iProtocolVersion); +} + +/* returns non-zero if the message has structured data, 0 otherwise */ +static inline sbool +MsgHasStructuredData(msg_t *pM) +{ + return (pM->pszStrucData == NULL) ? 0 : 1; +} /* ------------------------------ some inline functions ------------------------------ */ diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index 7cad3eae..743296b5 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -418,6 +418,8 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_CA_CERT_MISSING = -2329,/**< a CA cert is missing where one is required (e.g. TLS) */ RS_RET_CERT_MISSING = -2330,/**< a cert is missing where one is required (e.g. TLS) */ RS_RET_CERTKEY_MISSING = -2331,/**< a cert (private) key is missing where one is required (e.g. TLS) */ + RS_RET_STRUC_DATA_INVLD = -2349,/**< structured data is malformed */ + /* up to 2350 reserved for 7.4 */ RS_RET_QUEUE_CRY_DISK_ONLY = -2351,/**< crypto provider only supported for disk-associated queues */ RS_RET_NO_DATA = -2352,/**< file has no data; more a state than a real error */ diff --git a/tools/pmrfc3164.c b/tools/pmrfc3164.c index 4f469a2d..25964702 100644 --- a/tools/pmrfc3164.c +++ b/tools/pmrfc3164.c @@ -84,7 +84,7 @@ CODESTARTparse assert(pMsg->pszRawMsg != NULL); lenMsg = pMsg->iLenRawMsg - pMsg->offAfterPRI; /* note: offAfterPRI is already the number of PRI chars (do not add one!) */ p2parse = pMsg->pszRawMsg + pMsg->offAfterPRI; /* point to start of text, after PRI */ - setProtocolVersion(pMsg, 0); + setProtocolVersion(pMsg, MSG_LEGACY_PROTOCOL); /* Check to see if msg contains a timestamp. We start by assuming * that the message timestamp is the time of reception (which we diff --git a/tools/pmrfc5424.c b/tools/pmrfc5424.c index 9b5c6165..8e9510f3 100644 --- a/tools/pmrfc5424.c +++ b/tools/pmrfc5424.c @@ -227,7 +227,7 @@ CODESTARTparse ABORT_FINALIZE(RS_RET_COULD_NOT_PARSE); } DBGPRINTF("Message has RFC5424/syslog-protocol format.\n"); - setProtocolVersion(pMsg, 1); + setProtocolVersion(pMsg, MSG_RFC5424_PROTOCOL); p2parse += 2; lenMsg -= 2; |