summaryrefslogtreecommitdiffstats
path: root/syslogd.c
diff options
context:
space:
mode:
authorRainer Gerhards <rgerhards@adiscon.com>2007-07-22 16:03:45 +0000
committerRainer Gerhards <rgerhards@adiscon.com>2007-07-22 16:03:45 +0000
commit6b24fa20d4da8a57a2e34b1ca0c3159b93157e1e (patch)
treeb77862ccfb9c4b8a4987da934ccc3ef290e37afd /syslogd.c
parent70c56633497562c8c594cab8f2aa55dd1d7ca5fa (diff)
downloadrsyslog-6b24fa20d4da8a57a2e34b1ca0c3159b93157e1e.tar.gz
rsyslog-6b24fa20d4da8a57a2e34b1ca0c3159b93157e1e.tar.xz
rsyslog-6b24fa20d4da8a57a2e34b1ca0c3159b93157e1e.zip
moved file write output module to own set of code files
Diffstat (limited to 'syslogd.c')
-rw-r--r--syslogd.c1098
1 files changed, 8 insertions, 1090 deletions
diff --git a/syslogd.c b/syslogd.c
index cf88c117..8c1459f4 100644
--- a/syslogd.c
+++ b/syslogd.c
@@ -205,20 +205,22 @@
#endif
#include "rsyslog.h"
+#include "srUtils.h"
+#include "stringbuf.h"
+#include "syslogd-types.h"
#include "template.h"
#include "outchannel.h"
#include "syslogd.h"
#include "net.h" /* struct NetAddr */
-#include "stringbuf.h"
#include "parse.h"
-#include "srUtils.h"
#include "msg.h"
#include "tcpsyslog.h"
#include "omshell.h"
#include "omusrmsg.h"
#include "ommysql.h"
#include "omfwd.h"
+#include "omfile.h"
/* We define our own set of syslog defintions so that we
* do not need to rely on (possibly different) implementations.
@@ -386,13 +388,6 @@ int funix[MAXFUNIX] = { -1, }; /* read-only after startup */
#define TABLE_ALLPRI 0xFF /* Value to indicate all priorities in f_pmask */
#define LOG_MARK LOG_MAKEPRI(LOG_NFACILITIES, 0) /* mark "facility" */
-/* Flags to logmsg().
- */
-#define INTERNAL_MSG 0x001 /* msg generated by logmsgInternal() --> special handling */
-#define SYNC_FILE 0x002 /* do fsync on file after printing */
-#define ADDDATE 0x004 /* add a date to the message */
-#define MARK 0x008 /* this message is a mark */
-
/* This table lists the directive lines:
*/
static const char *directive_name_list[] = {
@@ -1606,512 +1601,6 @@ void getCurrTime(struct syslogTime *t)
t->OffsetHour = lBias / 3600;
t->OffsetMinute = lBias % 3600;
}
-
-/* Decode a priority into textual information like auth.emerg.
- * The variable pRes must point to a user-supplied buffer and
- * pResLen must contain its size. The pointer to the buffer
- * is also returned, what makes this functiona suitable for
- * use in printf-like functions.
- * Note: a buffer size of 20 characters is always sufficient.
- * Interface to this function changed 2007-06-15 by RGerhards
- */
-char *textpri(char *pRes, size_t pResLen, int pri)
-{
- syslogCODE *c_pri, *c_fac;
-
- assert(pRes != NULL);
- assert(pResLen > 0);
-
- for (c_fac = rs_facilitynames; c_fac->c_name && !(c_fac->c_val == LOG_FAC(pri)<<3); c_fac++);
- for (c_pri = rs_prioritynames; c_pri->c_name && !(c_pri->c_val == LOG_PRI(pri)); c_pri++);
-
- snprintf (pRes, pResLen, "%s.%s<%d>", c_fac->c_name, c_pri->c_name, pri);
-
- return pRes;
-}
-
-
-/* This function returns the current date in different
- * variants. It is used to construct the $NOW series of
- * system properties. The returned buffer must be freed
- * by the caller when no longer needed. If the function
- * can not allocate memory, it returns a NULL pointer.
- * Added 2007-07-10 rgerhards
- */
-typedef enum ENOWType { NOW_NOW, NOW_YEAR, NOW_MONTH, NOW_DAY, NOW_HOUR, NOW_MINUTE } eNOWType;
-#define tmpBUFSIZE 16 /* size of formatting buffer */
-static uchar *getNOW(eNOWType eNow)
-{
- uchar *pBuf;
- struct syslogTime t;
-
- if((pBuf = (uchar*) malloc(sizeof(uchar) * tmpBUFSIZE)) == NULL) {
- glblHadMemShortage = 1;
- return NULL;
- }
-
- getCurrTime(&t);
- switch(eNow) {
- case NOW_NOW:
- snprintf((char*) pBuf, tmpBUFSIZE, "%4.4d-%2.2d-%2.2d", t.year, t.month, t.day);
- break;
- case NOW_YEAR:
- snprintf((char*) pBuf, tmpBUFSIZE, "%4.4d", t.year);
- break;
- case NOW_MONTH:
- snprintf((char*) pBuf, tmpBUFSIZE, "%2.2d", t.month);
- break;
- case NOW_DAY:
- snprintf((char*) pBuf, tmpBUFSIZE, "%2.2d", t.day);
- break;
- case NOW_HOUR:
- snprintf((char*) pBuf, tmpBUFSIZE, "%2.2d", t.hour);
- break;
- case NOW_MINUTE:
- snprintf((char*) pBuf, tmpBUFSIZE, "%2.2d", t.minute);
- break;
- }
-
- return(pBuf);
-}
-#undef tmpBUFSIZE /* clean up */
-
-
-/* This function returns a string-representation of the
- * requested message property. This is a generic function used
- * to abstract properties so that these can be easier
- * queried. Returns NULL if property could not be found.
- * Actually, this function is a big if..elseif. What it does
- * is simply to map property names (from MonitorWare) to the
- * message object data fields.
- *
- * In case we need string forms of propertis we do not
- * yet have in string form, we do a memory allocation that
- * is sufficiently large (in all cases). Once the string
- * form has been obtained, it is saved until the Msg object
- * is finally destroyed. This is so that we save the processing
- * time in the (likely) case that this property is requested
- * again. It also saves us a lot of dynamic memory management
- * issues in the upper layers, because we so can guarantee that
- * the buffer will remain static AND available during the lifetime
- * of the object. Please note that both the max size allocation as
- * well as keeping things in memory might like look like a
- * waste of memory (some might say it actually is...) - we
- * deliberately accept this because performance is more important
- * to us ;)
- * rgerhards 2004-11-18
- * Parameter "bMustBeFreed" is set by this function. It tells the
- * caller whether or not the string returned must be freed by the
- * caller itself. It is is 0, the caller MUST NOT free it. If it is
- * 1, the caller MUST free 1. Handling this wrongly leads to either
- * a memory leak of a program abort (do to double-frees or frees on
- * the constant memory pool). So be careful to do it right.
- * rgerhards 2004-11-23
- * regular expression support contributed by Andres Riancho merged
- * on 2005-09-13
- * changed so that it now an be called without a template entry (NULL).
- * In this case, only the (unmodified) property is returned. This will
- * be used in selector line processing.
- * rgerhards 2005-09-15
- */
-static char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
- rsCStrObj *pCSPropName, unsigned short *pbMustBeFreed)
-{
- char *pName;
- char *pRes; /* result pointer */
- char *pBufStart;
- char *pBuf;
- int iLen;
-
-#ifdef FEATURE_REGEXP
- /* Variables necessary for regular expression matching */
- size_t nmatch = 2;
- regmatch_t pmatch[2];
-#endif
-
- assert(pMsg != NULL);
- assert(pbMustBeFreed != NULL);
-
- if(pCSPropName == NULL) {
- assert(pTpe != NULL);
- pName = pTpe->data.field.pPropRepl;
- } else {
- pName = (char*) rsCStrGetSzStr(pCSPropName);
- }
- *pbMustBeFreed = 0;
-
- /* sometimes there are aliases to the original MonitoWare
- * property names. These come after || in the ifs below. */
- if(!strcmp(pName, "msg")) {
- pRes = getMSG(pMsg);
- } else if(!strcmp(pName, "rawmsg")) {
- pRes = getRawMsg(pMsg);
- } else if(!strcmp(pName, "UxTradMsg")) {
- pRes = getUxTradMsg(pMsg);
- } else if(!strcmp(pName, "FROMHOST")) {
- pRes = getRcvFrom(pMsg);
- } else if(!strcmp(pName, "source")
- || !strcmp(pName, "HOSTNAME")) {
- pRes = getHOSTNAME(pMsg);
- } else if(!strcmp(pName, "syslogtag")) {
- pRes = getTAG(pMsg);
- } else if(!strcmp(pName, "PRI")) {
- pRes = getPRI(pMsg);
- } else if(!strcmp(pName, "PRI-text")) {
- pBuf = malloc(20 * sizeof(char));
- if(pBuf == NULL) {
- *pbMustBeFreed = 0;
- return "**OUT OF MEMORY**";
- } else {
- *pbMustBeFreed = 1;
- pRes = textpri(pBuf, 20, getPRIi(pMsg));
- }
- } else if(!strcmp(pName, "iut")) {
- pRes = "1"; /* always 1 for syslog messages (a MonitorWare thing;)) */
- } else if(!strcmp(pName, "syslogfacility")) {
- pRes = getFacility(pMsg);
- } else if(!strcmp(pName, "syslogfacility-text")) {
- pRes = getFacilityStr(pMsg);
- } else if(!strcmp(pName, "syslogseverity") || !strcmp(pName, "syslogpriority")) {
- pRes = getSeverity(pMsg);
- } else if(!strcmp(pName, "syslogseverity-text") || !strcmp(pName, "syslogpriority-text")) {
- pRes = getSeverityStr(pMsg);
- } else if(!strcmp(pName, "timegenerated")) {
- pRes = getTimeGenerated(pMsg, pTpe->data.field.eDateFormat);
- } else if(!strcmp(pName, "timereported")
- || !strcmp(pName, "TIMESTAMP")) {
- pRes = getTimeReported(pMsg, pTpe->data.field.eDateFormat);
- } else if(!strcmp(pName, "programname")) {
- pRes = getProgramName(pMsg);
- } else if(!strcmp(pName, "PROTOCOL-VERSION")) {
- pRes = getProtocolVersionString(pMsg);
- } else if(!strcmp(pName, "STRUCTURED-DATA")) {
- pRes = getStructuredData(pMsg);
- } else if(!strcmp(pName, "APP-NAME")) {
- pRes = getAPPNAME(pMsg);
- } else if(!strcmp(pName, "PROCID")) {
- pRes = getPROCID(pMsg);
- } else if(!strcmp(pName, "MSGID")) {
- pRes = getMSGID(pMsg);
- /* here start system properties (those, that do not relate to the message itself */
- } else if(!strcmp(pName, "$NOW")) {
- if((pRes = (char*) getNOW(NOW_NOW)) == NULL) {
- return "***OUT OF MEMORY***";
- } else
- *pbMustBeFreed = 1; /* all of these functions allocate dyn. memory */
- } else if(!strcmp(pName, "$YEAR")) {
- if((pRes = (char*) getNOW(NOW_YEAR)) == NULL) {
- return "***OUT OF MEMORY***";
- } else
- *pbMustBeFreed = 1; /* all of these functions allocate dyn. memory */
- } else if(!strcmp(pName, "$MONTH")) {
- if((pRes = (char*) getNOW(NOW_MONTH)) == NULL) {
- return "***OUT OF MEMORY***";
- } else
- *pbMustBeFreed = 1; /* all of these functions allocate dyn. memory */
- } else if(!strcmp(pName, "$DAY")) {
- if((pRes = (char*) getNOW(NOW_DAY)) == NULL) {
- return "***OUT OF MEMORY***";
- } else
- *pbMustBeFreed = 1; /* all of these functions allocate dyn. memory */
- } else if(!strcmp(pName, "$HOUR")) {
- if((pRes = (char*) getNOW(NOW_HOUR)) == NULL) {
- return "***OUT OF MEMORY***";
- } else
- *pbMustBeFreed = 1; /* all of these functions allocate dyn. memory */
- } else if(!strcmp(pName, "$MINUTE")) {
- if((pRes = (char*) getNOW(NOW_MINUTE)) == NULL) {
- return "***OUT OF MEMORY***";
- } else
- *pbMustBeFreed = 1; /* all of these functions allocate dyn. memory */
- } else {
- /* there is no point in continuing, we may even otherwise render the
- * error message unreadable. rgerhards, 2007-07-10
- */
- return "**INVALID PROPERTY NAME**";
- }
-
- /* If we did not receive a template pointer, we are already done... */
- if(pTpe == NULL) {
- return pRes;
- }
-
- /* Now check if we need to make "temporary" transformations (these
- * are transformations that do not go back into the message -
- * memory must be allocated for them!).
- */
-
- /* substring extraction */
- /* first we check if we need to extract by field number
- * rgerhards, 2005-12-22
- */
- if(pTpe->data.field.has_fields == 1) {
- size_t iCurrFld;
- char *pFld;
- char *pFldEnd;
- /* first, skip to the field in question. The field separator
- * is always one character and is stored in the template entry.
- */
- iCurrFld = 1;
- pFld = pRes;
- while(*pFld && iCurrFld < pTpe->data.field.iToPos) {
- /* skip fields until the requested field or end of string is found */
- while(*pFld && (uchar) *pFld != pTpe->data.field.field_delim)
- ++pFld; /* skip to field terminator */
- if(*pFld == pTpe->data.field.field_delim) {
- ++pFld; /* eat it */
- ++iCurrFld;
- }
- }
- dprintf("field requested %d, field found %d\n", pTpe->data.field.iToPos, iCurrFld);
-
- if(iCurrFld == pTpe->data.field.iToPos) {
- /* field found, now extract it */
- /* first of all, we need to find the end */
- pFldEnd = pFld;
- while(*pFldEnd && *pFldEnd != pTpe->data.field.field_delim)
- ++pFldEnd;
- --pFldEnd; /* we are already at the delimiter - so we need to
- * step back a little not to copy it as part of the field. */
- /* we got our end pointer, now do the copy */
- /* TODO: code copied from below, this is a candidate for a separate function */
- iLen = pFldEnd - pFld + 1; /* the +1 is for an actual char, NOT \0! */
- pBufStart = pBuf = malloc((iLen + 1) * sizeof(char));
- if(pBuf == NULL) {
- if(*pbMustBeFreed == 1)
- free(pRes);
- *pbMustBeFreed = 0;
- return "**OUT OF MEMORY**";
- }
- /* now copy */
- memcpy(pBuf, pFld, iLen);
- pBuf[iLen] = '\0'; /* terminate it */
- if(*pbMustBeFreed == 1)
- free(pRes);
- pRes = pBufStart;
- *pbMustBeFreed = 1;
- if(*(pFldEnd+1) != '\0')
- ++pFldEnd; /* OK, skip again over delimiter char */
- } else {
- /* field not found, return error */
- if(*pbMustBeFreed == 1)
- free(pRes);
- *pbMustBeFreed = 0;
- return "**FIELD NOT FOUND**";
- }
- } else if(pTpe->data.field.iFromPos != 0 || pTpe->data.field.iToPos != 0) {
- /* we need to obtain a private copy */
- int iFrom, iTo;
- iFrom = pTpe->data.field.iFromPos;
- iTo = pTpe->data.field.iToPos;
- /* need to zero-base to and from (they are 1-based!) */
- if(iFrom > 0)
- --iFrom;
- if(iTo > 0)
- --iTo;
- iLen = iTo - iFrom + 1; /* the +1 is for an actual char, NOT \0! */
- pBufStart = pBuf = malloc((iLen + 1) * sizeof(char));
- if(pBuf == NULL) {
- if(*pbMustBeFreed == 1)
- free(pRes);
- *pbMustBeFreed = 0;
- return "**OUT OF MEMORY**";
- }
- if(iFrom) {
- /* skip to the start of the substring (can't do pointer arithmetic
- * because the whole string might be smaller!!)
- */
- // ++iFrom; /* nbr of chars to skip! */
- while(*pRes && iFrom) {
- --iFrom;
- ++pRes;
- }
- }
- /* OK, we are at the begin - now let's copy... */
- while(*pRes && iLen) {
- *pBuf++ = *pRes;
- ++pRes;
- --iLen;
- }
- *pBuf = '\0';
- if(*pbMustBeFreed == 1)
- free(pRes);
- pRes = pBufStart;
- *pbMustBeFreed = 1;
-#ifdef FEATURE_REGEXP
- } else {
- /* Check for regular expressions */
- if (pTpe->data.field.has_regex != 0) {
- if (pTpe->data.field.has_regex == 2)
- /* Could not compile regex before! */
- return
- "**NO MATCH** **BAD REGULAR EXPRESSION**";
-
- dprintf("debug: String to match for regex is: %s\n",
- pRes);
-
- if (0 != regexec(&pTpe->data.field.re, pRes, nmatch,
- pmatch, 0)) {
- /* we got no match! */
- return "**NO MATCH**";
- } else {
- /* Match! */
- /* I need to malloc pB */
- int iLenBuf;
- char *pB;
-
- iLenBuf = pmatch[1].rm_eo - pmatch[1].rm_so;
- pB = (char *) malloc((iLenBuf + 1) * sizeof(char));
-
- if (pB == NULL) {
- if (*pbMustBeFreed == 1)
- free(pRes);
- *pbMustBeFreed = 0;
- return "**OUT OF MEMORY ALLOCATING pBuf**";
- }
-
- /* Lets copy the matched substring to the buffer */
- memcpy(pB, pRes + pmatch[1].rm_so, iLenBuf);
- pB[iLenBuf] = '\0';/* terminate string, did not happen before */
-
- if (*pbMustBeFreed == 1)
- free(pRes);
- pRes = pB;
- *pbMustBeFreed = 1;
- }
- }
-#endif /* #ifdef FEATURE_REGEXP */
- }
-
- /* case conversations (should go after substring, because so we are able to
- * work on the smallest possible buffer).
- */
- if(pTpe->data.field.eCaseConv != tplCaseConvNo) {
- /* we need to obtain a private copy */
- int iBufLen = strlen(pRes);
- char *pBStart;
- char *pB;
- pBStart = pB = malloc((iBufLen + 1) * sizeof(char));
- if(pB == NULL) {
- if(*pbMustBeFreed == 1)
- free(pRes);
- *pbMustBeFreed = 0;
- return "**OUT OF MEMORY**";
- }
- while(*pRes) {
- *pB++ = (pTpe->data.field.eCaseConv == tplCaseConvUpper) ?
- toupper(*pRes) : tolower(*pRes);
- /* currently only these two exist */
- ++pRes;
- }
- *pB = '\0';
- if(*pbMustBeFreed == 1)
- free(pRes);
- pRes = pBStart;
- *pbMustBeFreed = 1;
- }
-
- /* now do control character dropping/escaping/replacement
- * Only one of these can be used. If multiple options are given, the
- * result is random (though currently there obviously is an order of
- * preferrence, see code below. But this is NOT guaranteed.
- * RGerhards, 2006-11-17
- */
- if(pTpe->data.field.options.bDropCC) {
- char *pSrc = pRes;
- char *pDst = pRes;
-
- while(*pSrc) {
- if(!iscntrl((int) *pSrc))
- *pDst++ = *pSrc;
- ++pSrc;
- }
- *pDst = '\0';
- } else if(pTpe->data.field.options.bSpaceCC) {
- char *pB = pRes;
- while(*pB) {
- if(iscntrl((int) *pB))
- *pB = ' ';
- ++pB;
- }
- } else if(pTpe->data.field.options.bEscapeCC) {
- /* we must first count how many control charactes are
- * present, because we need this to compute the new string
- * buffer length. While doing so, we also compute the string
- * length.
- */
- int iNumCC = 0;
- int iLenBuf = 0;
- char *pB;
-
- for(pB = pRes ; *pB ; ++pB) {
- ++iLenBuf;
- if(iscntrl((int) *pB))
- ++iNumCC;
- }
-
- if(iNumCC > 0) { /* if 0, there is nothing to escape, so we are done */
- /* OK, let's do the escaping... */
- char *pBStart;
- char szCCEsc[8]; /* buffer for escape sequence */
- int i;
-
- iLenBuf += iNumCC * 4;
- pBStart = pB = malloc((iLenBuf + 1) * sizeof(char));
- if(pB == NULL) {
- if(*pbMustBeFreed == 1)
- free(pRes);
- *pbMustBeFreed = 0;
- return "**OUT OF MEMORY**";
- }
- while(*pRes) {
- if(iscntrl((int) *pRes)) {
- snprintf(szCCEsc, sizeof(szCCEsc), "#%3.3d", *pRes);
- for(i = 0 ; i < 4 ; ++i)
- *pB++ = szCCEsc[i];
- } else {
- *pB++ = *pRes;
- }
- ++pRes;
- }
- *pB = '\0';
- if(*pbMustBeFreed == 1)
- free(pRes);
- pRes = pBStart;
- *pbMustBeFreed = 1;
- }
- }
-
- /* Now drop last LF if present (pls note that this must not be done
- * if bEscapeCC was set!
- */
- if(pTpe->data.field.options.bDropLastLF && !pTpe->data.field.options.bEscapeCC) {
- int iLn = strlen(pRes);
- char *pB;
- if(*(pRes + iLn - 1) == '\n') {
- /* we have a LF! */
- /* check if we need to obtain a private copy */
- if(pbMustBeFreed == 0) {
- /* ok, original copy, need a private one */
- pB = malloc((iLn + 1) * sizeof(char));
- if(pB == NULL) {
- if(*pbMustBeFreed == 1)
- free(pRes);
- *pbMustBeFreed = 0;
- return "**OUT OF MEMORY**";
- }
- memcpy(pB, pRes, iLn - 1);
- pRes = pB;
- *pbMustBeFreed = 1;
- }
- *(pRes + iLn - 1) = '\0'; /* drop LF ;) */
- }
- }
-
- /*dprintf("MsgGetProp(\"%s\"): \"%s\"\n", pName, pRes); only for verbose debug logging */
- return(pRes);
-}
-
/* rgerhards 2004-11-09: end of helper routines. On to the
* "real" code ;)
*/
@@ -2384,7 +1873,7 @@ static char **crunch_list(char *list)
}
-static void untty()
+void untty(void)
#ifdef HAVE_SETSID
{
if ( !Debug ) {
@@ -3582,129 +3071,6 @@ void logmsg(int pri, msg_t *pMsg, int flags)
}
-/* Helper to doSQLEscape. This is called if doSQLEscape
- * runs out of memory allocating the escaped string.
- * Then we are in trouble. We can
- * NOT simply return the unmodified string because this
- * may cause SQL injection. But we also can not simply
- * abort the run, this would be a DoS. I think an appropriate
- * measure is to remove the dangerous \' characters. We
- * replace them by \", which will break the message and
- * signatures eventually present - but this is the
- * best thing we can do now (or does anybody
- * have a better idea?). rgerhards 2004-11-23
- * added support for "escapeMode" (so doSQLEscape for details).
- * if mode = 1, then backslashes are changed to slashes.
- * rgerhards 2005-09-22
- */
-void doSQLEmergencyEscape(register char *p, int escapeMode)
-{
- while(*p) {
- if(*p == '\'')
- *p = '"';
- else if((escapeMode == 1) && (*p == '\\'))
- *p = '/';
- ++p;
- }
-}
-
-
-/* SQL-Escape a string. Single quotes are found and
- * replaced by two of them. A new buffer is allocated
- * for the provided string and the provided buffer is
- * freed. The length is updated. Parameter pbMustBeFreed
- * is set to 1 if a new buffer is allocated. Otherwise,
- * it is left untouched.
- * --
- * We just discovered a security issue. MySQL is so
- * "smart" to not only support the standard SQL mechanism
- * for escaping quotes, but to also provide its own (using
- * c-type syntax with backslashes). As such, it is actually
- * possible to do sql injection via rsyslogd. The cure is now
- * to escape backslashes, too. As we have found on the web, some
- * other databases seem to be similar "smart" (why do we have standards
- * at all if they are violated without any need???). Even better, MySQL's
- * smartness depends on config settings. So we add a new option to this
- * function that allows the caller to select if they want to standard or
- * "smart" encoding ;)
- * new parameter escapeMode is 0 - standard sql, 1 - "smart" engines
- * 2005-09-22 rgerhards
- */
-void doSQLEscape(char **pp, size_t *pLen, unsigned short *pbMustBeFreed, int escapeMode)
-{
- char *p;
- int iLen;
- rsCStrObj *pStrB;
- uchar *pszGenerated;
-
- assert(pp != NULL);
- assert(*pp != NULL);
- assert(pLen != NULL);
- assert(pbMustBeFreed != NULL);
-
- /* first check if we need to do anything at all... */
- if(escapeMode == 0)
- for(p = *pp ; *p && *p != '\'' ; ++p)
- ;
- else
- for(p = *pp ; *p && *p != '\'' && *p != '\\' ; ++p)
- ;
- /* when we get out of the loop, we are either at the
- * string terminator or the first \'. */
- if(*p == '\0')
- return; /* nothing to do in this case! */
-
- p = *pp;
- iLen = *pLen;
- if((pStrB = rsCStrConstruct()) == NULL) {
- /* oops - no mem ... Do emergency... */
- doSQLEmergencyEscape(p, escapeMode);
- return;
- }
-
- while(*p) {
- if(*p == '\'') {
- if(rsCStrAppendChar(pStrB, (escapeMode == 0) ? '\'' : '\\') != RS_RET_OK) {
- doSQLEmergencyEscape(*pp, escapeMode);
- rsCStrFinish(pStrB);
- if((pszGenerated = rsCStrConvSzStrAndDestruct(pStrB)) != NULL)
- free(pszGenerated);
- return;
- }
- iLen++; /* reflect the extra character */
- } else if((escapeMode == 1) && (*p == '\\')) {
- if(rsCStrAppendChar(pStrB, '\\') != RS_RET_OK) {
- doSQLEmergencyEscape(*pp, escapeMode);
- rsCStrFinish(pStrB);
- if((pszGenerated = rsCStrConvSzStrAndDestruct(pStrB)) != NULL)
- free(pszGenerated);
- return;
- }
- iLen++; /* reflect the extra character */
- }
- if(rsCStrAppendChar(pStrB, *p) != RS_RET_OK) {
- doSQLEmergencyEscape(*pp, escapeMode);
- rsCStrFinish(pStrB);
- if((pszGenerated = rsCStrConvSzStrAndDestruct(pStrB)) != NULL)
- free(pszGenerated);
- return;
- }
- ++p;
- }
- rsCStrFinish(pStrB);
- if((pszGenerated = rsCStrConvSzStrAndDestruct(pStrB)) == NULL) {
- doSQLEmergencyEscape(*pp, escapeMode);
- return;
- }
-
- if(*pbMustBeFreed)
- free(*pp); /* discard previous value */
-
- *pp = (char*) pszGenerated;
- *pLen = iLen;
- *pbMustBeFreed = 1;
-}
-
/* create a string from the provided iovec. This can
* be called by all functions who need the template
@@ -3860,446 +3226,6 @@ void iovCreate(selector_t *f)
return;
}
-/* This functions converts a template into a string. It should
- * actually be in template.c, but this requires larger re-structuring
- * of the code (because all the property-access functions are static
- * to this module). I have placed it next to the iov*() functions, as
- * it is somewhat similiar in what it does.
- *
- * The function takes a pointer to a template and a pointer to a msg object.
- * It the creates a string based on the template definition. A pointer
- * to that string is returned to the caller. The caller MUST FREE that
- * pointer when it is no longer needed. If the function fails, NULL
- * is returned.
- * If memory allocation fails in this function, we silently return
- * NULL. The reason is that we can not do anything against it. And
- * if we raise an alert, the memory situation might become even
- * worse. So we prefer to let the caller deal with it.
- * rgerhards, 2007-07-03
- */
-static uchar *tplToString(struct template *pTpl, msg_t *pMsg)
-{
- struct templateEntry *pTpe;
- rsCStrObj *pCStr;
- unsigned short bMustBeFreed;
- char *pVal;
- size_t iLenVal;
- rsRetVal iRet;
-
- assert(pTpl != NULL);
- assert(pMsg != NULL);
-
- /* loop through the template. We obtain one value
- * and copy it over to our dynamic string buffer. Then, we
- * free the obtained value (if requested). We continue this
- * loop until we got hold of all values.
- */
- if((pCStr = rsCStrConstruct()) == NULL) {
- dprintf("memory shortage, tplToString failed\n");
- return NULL;
- }
-
- pTpe = pTpl->pEntryRoot;
- while(pTpe != NULL) {
- if(pTpe->eEntryType == CONSTANT) {
- if((iRet = rsCStrAppendStrWithLen(pCStr,
- (uchar *) pTpe->data.constant.pConstant,
- pTpe->data.constant.iLenConstant)
- ) != RS_RET_OK) {
- dprintf("error %d during tplToString()\n", iRet);
- /* it does not make sense to continue now */
- rsCStrDestruct(pCStr);
- return NULL;
- }
- } else if(pTpe->eEntryType == FIELD) {
- pVal = (char*) MsgGetProp(pMsg, pTpe, NULL, &bMustBeFreed);
- iLenVal = strlen(pVal);
- /* we now need to check if we should use SQL option. In this case,
- * we must go over the generated string and escape '\'' characters.
- * rgerhards, 2005-09-22: the option values below look somewhat misplaced,
- * but they are handled in this way because of legacy (don't break any
- * existing thing).
- */
- if(pTpl->optFormatForSQL == 1)
- doSQLEscape(&pVal, &iLenVal, &bMustBeFreed, 1);
- else if(pTpl->optFormatForSQL == 2)
- doSQLEscape(&pVal, &iLenVal, &bMustBeFreed, 0);
- /* value extracted, so lets copy */
- if((iRet = rsCStrAppendStrWithLen(pCStr, (uchar*) pVal, iLenVal)) != RS_RET_OK) {
- dprintf("error %d during tplToString()\n", iRet);
- /* it does not make sense to continue now */
- rsCStrDestruct(pCStr);
- if(bMustBeFreed)
- free(pVal);
- return NULL;
- }
- if(bMustBeFreed)
- free(pVal);
- }
- pTpe = pTpe->pNext;
- }
-
- /* we are done with the template, now let's convert the result into a
- * "real" (usable) string and discard the helper structures.
- */
- rsCStrFinish(pCStr);
- return rsCStrConvSzStrAndDestruct(pCStr);
-}
-
-
-/* rgerhards 2005-06-21: Try to resolve a size limit
- * situation. This first runs the command, and then
- * checks if we are still above the treshold.
- * returns 0 if ok, 1 otherwise
- * TODO: consider moving the initial check in here, too
- */
-int resolveFileSizeLimit(selector_t *f)
-{
- uchar *pParams;
- uchar *pCmd;
- uchar *p;
- off_t actualFileSize;
- assert(f != NULL);
-
- if(f->f_un.f_file.f_sizeLimitCmd == NULL)
- return 1; /* nothing we can do in this case... */
-
- /* the execProg() below is probably not great, but at least is is
- * fairly secure now. Once we change the way file size limits are
- * handled, we should also revisit how this command is run (and
- * with which parameters). rgerhards, 2007-07-20
- */
- /* we first check if we have command line parameters. We assume this,
- * when we have a space in the program name. If we find it, everything after
- * the space is treated as a single argument.
- */
- if((pCmd = (uchar*)strdup((char*)f->f_un.f_file.f_sizeLimitCmd)) == NULL) {
- /* there is not much we can do - we make syslogd close the file in this case */
- glblHadMemShortage = 1;
- return 1;
- }
-
- for(p = pCmd ; *p && *p != ' ' ; ++p) {
- /* JUST SKIP */
- }
-
- if(*p == ' ') {
- *p = '\0'; /* pretend string-end */
- pParams = p+1;
- } else
- pParams = NULL;
-
- execProg(pCmd, 1, pParams);
-
- f->f_file = open(f->f_un.f_file.f_fname, O_WRONLY|O_APPEND|O_CREAT|O_NOCTTY,
- f->f_un.f_file.fCreateMode);
-
- actualFileSize = lseek(f->f_file, 0, SEEK_END);
- if(actualFileSize >= f->f_un.f_file.f_sizeLimit) {
- /* OK, it didn't work out... */
- return 1;
- }
-
- return 0;
-}
-
-
-/* This function deletes an entry from the dynamic file name
- * cache. A pointer to the cache must be passed in as well
- * as the index of the to-be-deleted entry. This index may
- * point to an unallocated entry, in whcih case the
- * function immediately returns. Parameter bFreeEntry is 1
- * if the entry should be free()ed and 0 if not.
- */
-static void dynaFileDelCacheEntry(dynaFileCacheEntry **pCache, int iEntry, int bFreeEntry)
-{
- assert(pCache != NULL);
-
- if(pCache[iEntry] == NULL)
- return;
-
- dprintf("Removed entry %d for file '%s' from dynaCache.\n", iEntry,
- pCache[iEntry]->pName == NULL ? "[OPEN FAILED]" : (char*)pCache[iEntry]->pName);
- /* if the name is NULL, this is an improperly initilized entry which
- * needs to be discarded. In this case, neither the file is to be closed
- * not the name to be freed.
- */
- if(pCache[iEntry]->pName != NULL) {
- close(pCache[iEntry]->fd);
- free(pCache[iEntry]->pName);
- pCache[iEntry]->pName = NULL;
- }
-
- if(bFreeEntry) {
- free(pCache[iEntry]);
- pCache[iEntry] = NULL;
- }
-}
-
-
-/* This function frees the dynamic file name cache.
- */
-static void dynaFileFreeCache(selector_t *f)
-{
- register int i;
- assert(f != NULL);
-
- for(i = 0 ; i < f->f_un.f_file.iCurrCacheSize ; ++i) {
- dynaFileDelCacheEntry(f->f_un.f_file.dynCache, i, 1);
- }
-
- free(f->f_un.f_file.dynCache);
-}
-
-
-/* This function handles dynamic file names. It generates a new one
- * based on the current message, checks if that file is already open
- * and, if not, does everything needed to switch to the new one.
- * Function returns 0 if all went well and non-zero otherwise.
- * On successful return f->f_file must point to the correct file to
- * be written.
- * This is a helper to writeFile(). rgerhards, 2007-07-03
- */
-static int prepareDynFile(selector_t *f)
-{
- uchar *newFileName;
- time_t ttOldest; /* timestamp of oldest element */
- int iOldest;
- int i;
- int iFirstFree;
- dynaFileCacheEntry **pCache;
-
- assert(f != NULL);
- if((newFileName = tplToString(f->f_un.f_file.pTpl, f->f_pMsg)) == NULL) {
- /* memory shortage - there is nothing we can do to resolve it.
- * We silently ignore it, this is probably the best we can do.
- */
- glblHadMemShortage = TRUE;
- dprintf("prepareDynfile(): could not create file name, discarding this request\n");
- return -1;
- }
-
- pCache = f->f_un.f_file.dynCache;
-
- /* first check, if we still have the current file
- * I *hope* this will be a performance enhancement.
- */
- if( (f->f_un.f_file.iCurrElt != -1)
- && !strcmp((char*) newFileName,
- (char*) pCache[f->f_un.f_file.iCurrElt])) {
- /* great, we are all set */
- free(newFileName);
- pCache[f->f_un.f_file.iCurrElt]->lastUsed = time(NULL); /* update timestamp for LRU */
- return 0;
- }
-
- /* ok, no luck. Now let's search the table if we find a matching spot.
- * While doing so, we also prepare for creation of a new one.
- */
- iFirstFree = -1; /* not yet found */
- iOldest = 0; /* we assume the first element to be the oldest - that will change as we loop */
- ttOldest = time(NULL) + 1; /* there must always be an older one */
- for(i = 0 ; i < f->f_un.f_file.iCurrCacheSize ; ++i) {
- if(pCache[i] == NULL) {
- if(iFirstFree == -1)
- iFirstFree = i;
- } else { /* got an element, let's see if it matches */
- if(!strcmp((char*) newFileName, (char*) pCache[i]->pName)) {
- /* we found our element! */
- f->f_file = pCache[i]->fd;
- f->f_un.f_file.iCurrElt = i;
- free(newFileName);
- pCache[i]->lastUsed = time(NULL); /* update timestamp for LRU */
- return 0;
- }
- /* did not find it - so lets keep track of the counters for LRU */
- if(pCache[i]->lastUsed < ttOldest) {
- ttOldest = pCache[i]->lastUsed;
- iOldest = i;
- }
- }
- }
-
- /* we have not found an entry */
- if(iFirstFree == -1 && (f->f_un.f_file.iCurrCacheSize < f->f_un.f_file.iDynaFileCacheSize)) {
- /* there is space left, so set it to that index */
- iFirstFree = f->f_un.f_file.iCurrCacheSize++;
- }
-
- if(iFirstFree == -1) {
- dynaFileDelCacheEntry(pCache, iOldest, 0);
- iFirstFree = iOldest; /* this one *is* now free ;) */
- } else {
- /* we need to allocate memory for the cache structure */
- pCache[iFirstFree] = (dynaFileCacheEntry*) calloc(1, sizeof(dynaFileCacheEntry));
- if(pCache[iFirstFree] == NULL) {
- glblHadMemShortage = TRUE;
- dprintf("prepareDynfile(): could not alloc mem, discarding this request\n");
- free(newFileName);
- return -1;
- }
- }
-
- /* Ok, we finally can open the file */
- if(access((char*)newFileName, F_OK) == 0) {
- /* file already exists */
- f->f_file = open((char*) newFileName, O_WRONLY|O_APPEND|O_CREAT|O_NOCTTY,
- f->f_un.f_file.fCreateMode);
- } else {
- /* file does not exist, create it (and eventually parent directories */
- if(f->f_un.f_file.bCreateDirs) {
- /* we fist need to create parent dirs if they are missing
- * We do not report any errors here ourselfs but let the code
- * fall through to error handler below.
- */
- if(makeFileParentDirs(newFileName, strlen((char*)newFileName),
- f->f_un.f_file.fDirCreateMode, f->f_un.f_file.dirUID,
- f->f_un.f_file.dirGID, f->f_un.f_file.bFailOnChown) == 0) {
- f->f_file = open((char*) newFileName, O_WRONLY|O_APPEND|O_CREAT|O_NOCTTY,
- f->f_un.f_file.fCreateMode);
- if(f->f_file != -1) {
- /* check and set uid/gid */
- if(f->f_un.f_file.fileUID != (uid_t)-1 || f->f_un.f_file.fileGID != (gid_t) -1) {
- /* we need to set owner/group */
- if(fchown(f->f_file, f->f_un.f_file.fileUID,
- f->f_un.f_file.fileGID) != 0) {
- if(f->f_un.f_file.bFailOnChown) {
- int eSave = errno;
- close(f->f_file);
- f->f_file = -1;
- errno = eSave;
- }
- /* we will silently ignore the chown() failure
- * if configured to do so.
- */
- }
- }
- }
- }
- }
- }
-
- /* file is either open now or an error state set */
- if(f->f_file == -1) {
- /* do not report anything if the message is an internally-generated
- * message. Otherwise, we could run into a never-ending loop. The bad
- * news is that we also lose errors on startup messages, but so it is.
- */
- if(f->f_pMsg->msgFlags & INTERNAL_MSG)
- dprintf("Could not open dynaFile, discarding message\n");
- else
- logerrorSz("Could not open dynamic file '%s' - discarding message", (char*)newFileName);
- free(newFileName);
- dynaFileDelCacheEntry(pCache, iFirstFree, 1);
- return -1;
- }
-
- pCache[iFirstFree]->fd = f->f_file;
- pCache[iFirstFree]->pName = newFileName;
- pCache[iFirstFree]->lastUsed = time(NULL);
- f->f_un.f_file.iCurrElt = iFirstFree;
- dprintf("Added new entry %d for file cache, file '%s'.\n",
- iFirstFree, newFileName);
-
- return 0;
-}
-
-
-/* rgerhards 2004-11-11: write to a file output. This
- * will be called for all outputs using file semantics,
- * for example also for pipes.
- */
-void writeFile(selector_t *f)
-{
- off_t actualFileSize;
-
- assert(f != NULL);
-
- /* first check if we have a dynamic file name and, if so,
- * check if it still is ok or a new file needs to be created
- */
- if(f->f_un.f_file.bDynamicName) {
- if(prepareDynFile(f) != 0)
- return;
- }
-
- /* create the message based on format specified */
- iovCreate(f);
-again:
- /* check if we have a file size limit and, if so,
- * obey to it.
- */
- if(f->f_un.f_file.f_sizeLimit != 0) {
- actualFileSize = lseek(f->f_file, 0, SEEK_END);
- if(actualFileSize >= f->f_un.f_file.f_sizeLimit) {
- char errMsg[256];
- /* for now, we simply disable a file once it is
- * beyond the maximum size. This is better than having
- * us aborted by the OS... rgerhards 2005-06-21
- */
- (void) close(f->f_file);
- /* try to resolve the situation */
- if(resolveFileSizeLimit(f) != 0) {
- /* didn't work out, so disable... */
- f->f_type = F_UNUSED;
- snprintf(errMsg, sizeof(errMsg),
- "no longer writing to file %s; grown beyond configured file size of %lld bytes, actual size %lld - configured command did not resolve situation",
- f->f_un.f_file.f_fname, (long long) f->f_un.f_file.f_sizeLimit, (long long) actualFileSize);
- errno = 0;
- logerror(errMsg);
- return;
- } else {
- snprintf(errMsg, sizeof(errMsg),
- "file %s had grown beyond configured file size of %lld bytes, actual size was %lld - configured command resolved situation",
- f->f_un.f_file.f_fname, (long long) f->f_un.f_file.f_sizeLimit, (long long) actualFileSize);
- errno = 0;
- logerror(errMsg);
- }
- }
- }
-
- if (writev(f->f_file, f->f_iov, f->f_iIovUsed) < 0) {
- int e = errno;
-
- /* If a named pipe is full, just ignore it for now
- - mrn 24 May 96 */
- if (f->f_type == F_PIPE && e == EAGAIN)
- return;
-
- /* If the filesystem is filled up, just ignore
- * it for now and continue writing when possible
- * based on patch for sysklogd by Martin Schulze on 2007-05-24
- */
- if (f->f_type == F_FILE && e == ENOSPC)
- return;
-
- (void) close(f->f_file);
- /*
- * Check for EBADF on TTY's due to vhangup()
- * Linux uses EIO instead (mrn 12 May 96)
- */
- if ((f->f_type == F_TTY || f->f_type == F_CONSOLE)
-#ifdef linux
- && e == EIO) {
-#else
- && e == EBADF) {
-#endif
- f->f_file = open(f->f_un.f_file.f_fname, O_WRONLY|O_APPEND|O_NOCTTY);
- if (f->f_file < 0) {
- f->f_type = F_UNUSED;
- logerror(f->f_un.f_file.f_fname);
- } else {
- untty();
- goto again;
- }
- } else {
- f->f_type = F_UNUSED;
- errno = e;
- logerror(f->f_un.f_file.f_fname);
- }
- } else if (f->f_flags & SYNC_FILE)
- fsync(f->f_file);
-}
/* rgerhards 2004-11-09: fprintlog() is the actual driver for
* the output channel. It receives the channel description (f) as
@@ -4373,12 +3299,7 @@ void fprintlog(register selector_t *f)
case F_PIPE:
printf(" (%s)\n", f->f_un.f_file.f_fname);
f->f_time = now; /* we need this for message repeation processing */
- /* f->f_file == -1 is an indicator that the we couldn't
- * open the file at startup. For dynaFiles, this is ok,
- * all others are doomed.
- */
- if(f->f_un.f_file.bDynamicName || (f->f_file != -1))
- writeFile(f);
+ doActionFile(f);
break;
case F_USERS:
@@ -4396,7 +3317,7 @@ void fprintlog(register selector_t *f)
case F_SHELL: /* shell support by bkalkbrenner 2005-09-20 */
f->f_time = now;
- doActionShell(f, now);
+ doActionShell(f);
break;
} /* switch */
@@ -5288,10 +4209,7 @@ static void init()
case F_PIPE:
case F_TTY:
case F_CONSOLE:
- if(f->f_un.f_file.bDynamicName) {
- dynaFileFreeCache(f);
- } else
- close(f->f_file);
+ freeInstanceFile(f);
break;
case F_FORW:
freeaddrinfo(f->f_un.f_forw.f_addr);