Merge lp:~cjwatson/ubuntu/trusty/rsyslog/repair-groups into lp:ubuntu/trusty/rsyslog

Proposed by Colin Watson
Status: Merged
Merged at revision: 57
Proposed branch: lp:~cjwatson/ubuntu/trusty/rsyslog/repair-groups
Merge into: lp:ubuntu/trusty/rsyslog
Diff against target: 1533 lines (+1468/-0)
7 files modified
.pc/10-initgroups.patch/runtime/rsconf.c (+1386/-0)
.pc/applied-patches (+1/-0)
debian/changelog (+12/-0)
debian/patches/10-initgroups.patch (+44/-0)
debian/patches/series (+1/-0)
debian/rsyslog.postinst (+6/-0)
runtime/rsconf.c (+18/-0)
To merge this branch: bzr merge lp:~cjwatson/ubuntu/trusty/rsyslog/repair-groups
Reviewer Review Type Date Requested Status
Martin Pitt Approve
Review via email: mp+197705@code.launchpad.net

Description of the change

This fixes log file creation in trusty. IRC conversation for the record:

<pitti> xnox_, slangasek: I adjusted bug 1257633; apparently rsyslog is now completely unable to create any of its logs?
<ubottu> bug 1257633 in rsyslog (Ubuntu Trusty) "/var/log/syslog and others don't exist on fresh installation of Trusty." [Critical,Confirmed] https://launchpad.net/bugs/1257633
<cjwatson> pitti: I'm investigating that at the moment, bug 1256695
<ubottu> bug 1256695 in rsyslog (Ubuntu) "Trusty desktop Installation logs are not copied to /var/log/installer/" [Undecided,Confirmed] https://launchpad.net/bugs/1256695
<cjwatson> pitti: it seems to be to do with a rearrangement of how privilege-dropping works
<pitti> cjwatson: ah, thank you
<cjwatson> +- bugfix: do not open files with full privileges, if privs will be dropped
<cjwatson> + This make the privilege drop code more bulletproof, but breaks Ubuntu's
<cjwatson> + work-around for log files created by external programs with the wrong
<cjwatson> + user and/or group. Note that it was long said that this "functionality"
<cjwatson> + would break once we go for serious privilege drop code, so hopefully
<cjwatson> + nobody still depends on it (and, if so, they lost...).
<cjwatson> e.g.
<cjwatson> so, uh, oh dear
<pitti> cjwatson: ah, that's because /var/log is root:root 755?
<cjwatson> Yeah, it might be as simple as changing that
<cjwatson> I see that rsyslog-controlled files there were already syslog:adm
<pitti> rsyslog runs as syslog:syslog, so we could just make it root:syslog 775?
<cjwatson> that's certainly sufficient to make it work
<cjwatson> I can't immediately think of a reason not to do that
<cjwatson> what do other distros do?
<cjwatson> it's not clear to me that Fedora drops privileges, looking only at its rsyslog packaging
<pitti> cjwatson: do they even use rsyslog still? it's not all journald now?
<pitti> I understand you can still install it, but it's not by default
<cjwatson> Nor Gentoo
<cjwatson> pitti: could be
<cjwatson> pitti: however, there's a further difficulty
<cjwatson> pitti: if I just change the /var/log perms, then it appears to work, but /var/log/syslog is created syslog:syslog not syslog:adm, so the ability for users in group adm to read logs has been broken
<cjwatson> (and mode 640)
<cjwatson> pitti: this is related to bug 484336
<ubottu> bug 484336 in rsyslog (Ubuntu) "/etc/rsyslog.conf permissions incorrect/missing for creation of dynamic files" [Undecided,Confirmed] https://launchpad.net/bugs/484336
<pitti> cjwatson: ah, so we'd need to put user "syslog" into "adm", or perhaps even make that its primary group?
<pitti> (that's ugly to do on upgrades, though)
<cjwatson> or run rsyslogd as group adm
<cjwatson> I don't know which is worse
<cjwatson> we have to do one of those if rsyslogd is no longer willing to use raised privileges to open files, though ...
<cjwatson> it wouldn't need to be syslog's primary group
<cjwatson> syslog is a dynamic user owned by the rsyslog package, so it's not necessarily horrible to change its supplementary groups
<cjwatson> hmm, that doesn't fix the ownership though
<pitti> right, with a non-primary groupd it'd need a source patch
<cjwatson> oh, because rsyslogd doesn't setgroups when it drops privileges?
<cjwatson> or rather it does but only to deliberately drop supplementary groups
<pitti> cjwatson: no, I meant if it creates a new file, it would need to explicitly set their group to "adm", unless that's its primary group?
<cjwatson> it's already configured with FileGroup to do that
<pitti> ah, of course; sorry
<cjwatson> but the problem is that it can only do the chown() if it did the appropriate setgroups at privdrop
<cjwatson> http://kb.monitorware.com/feature-request-privdroptogroup-setgroups-initgroups-t11491.html
<pitti> $PrivDropToGroup syslog
<pitti> so that's what's not keeping the aux groups
<cjwatson> right. now the questions would be (a) would changing that to adm expose rsyslog to any malice by users in group adm? (b) might there be systems right now that are relying on rsyslog being able to open files in group syslog?
<pitti> I don't see an immediate case for (a) as "adm" is pretty much only a "get read privs" group, but (b) certainly might happen
<cjwatson> the link above has an example of situations where you want rsyslogd to be able to set different log files to be owned by different groups
<pitti> cjwatson: TBH it seems safer to me to change the code to not drop the aux groups
<cjwatson> dropping the aux groups is required to drop the root group, but it could call initgroups afterwards
<cjwatson> pitti: Considering something like http://paste.ubuntu.com/6519272/
<pitti> cjwatson: I'm a bit rusty on the order of the various set* calls; does initgroups() come before or after setgid()?
<pitti> cjwatson: AFAIR, you have to setgid(), then initgroups(), then setuid(), right?
<cjwatson> pitti: rsyslog calls doDropPrivGid then doDropPrivUid
<pitti> the patch looks like initgroups() would come after set[ug]id?
<pitti> ah, so these two hunks are not from one functino
<cjwatson> pitti: doDropPrivGid already calls setgroups before setgid to discard the previously-held supplementary groups
<cjwatson> pitti: they are
<pitti> cjwatson: ack; LGTM then, thank you!
<cjwatson> pitti: the important bit is that you have to drop the old groups before you lose the ability to do so
<pitti> cjwatson: but this is still missing a chgrp syslog /var/log, isn't it?
<cjwatson> pitti: I think initgroups is fine after setuid
<cjwatson> pitti: oh yes good point
<pitti> cjwatson: after setuid> that's surprising; that sounds like increasing privileges after you dropped them and shouldn't be able to get them any more?
<cjwatson> I think you can gain your own supplementary groups ... but wait, something just occurred to me
<pitti> cjwatson: (and chmod 775)
<cjwatson> /var/log must not be owned by group adm
<cjwatson> because if we do that then users in group adm will be able to add files to it
<cjwatson> which is not expected
<pitti> no, adm group members must nto be able to write there
<pitti> that's why I thought root:syslog would be better
<cjwatson> oh, right, yeah, too many pieces
<pitti> so that rsyslog can write into it, but no real users
 * pitti adds to this TODO list to create an autopkgtest for rsyslog to cover new logs, log rotation, etc.
<cjwatson> http://paste.ubuntu.com/6519302/ then
<pitti> cjwatson: chmod g+w /var/log ?
<cjwatson> added
<cjwatson> pitti: hm, you were right earlier, setgroups (called by initgroups) requires the CAP_SETGID capability
<cjwatson> so I'll move that before the setuid
<pitti> ok, that's relieving (would be weird otherwise)
<cjwatson> pitti: OK, so after some fixups this basically works, but there's an amusing complication
<cjwatson> pitti: On upgrade, we restart rsyslog in postinst rather than stop in prerm / start in postinst, for generally obvious reasons
<cjwatson> pitti: But this means that when it restarts it tries to log one final message to say it's shutting down (and others might racily be logged, of course)
<cjwatson> pitti: And on a system without /var/log/syslog, that last message now gets successfully written (since we just adjusted permissions) but /var/log/syslog ends up as syslog:syslog (since we hadn't yet completed the restart with supplementary groups)
<cjwatson> pitti: So, I don't know; I suppose we could choose to not care because it's only been a problem for five days or so and it would go away at the next logrotate
<cjwatson> pitti: wdyt?
<pitti> cjwatson: re (sorry, lunch)
<pitti> cjwatson: TBH I'd go with the "don't care" approach, as it didn't affect any stables
<pitti> cjwatson: and in trusty, logs are already broken anyway
<pitti> cjwatson: i. e. the fully "correct" solution would be to create the file in preinst with the correct permissions on upgrade?
<cjwatson> pitti: well, except that the race case could involve log messages going to any log file
<cjwatson> I'm cool with "don't care" if you are :-)
<pitti> I am
<pitti> the main conclusion I draw from this is "this needs an autopkgtest" :)

To post a comment you must log in.
Revision history for this message
Martin Pitt (pitti) wrote :

Looks good to me, thanks!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory '.pc/10-initgroups.patch'
2=== added directory '.pc/10-initgroups.patch/runtime'
3=== added file '.pc/10-initgroups.patch/runtime/rsconf.c'
4--- .pc/10-initgroups.patch/runtime/rsconf.c 1970-01-01 00:00:00 +0000
5+++ .pc/10-initgroups.patch/runtime/rsconf.c 2013-12-04 13:07:52 +0000
6@@ -0,0 +1,1386 @@
7+/* rsconf.c - the rsyslog configuration system.
8+ *
9+ * Module begun 2011-04-19 by Rainer Gerhards
10+ *
11+ * Copyright 2011-2012 Adiscon GmbH.
12+ *
13+ * This file is part of the rsyslog runtime library.
14+ *
15+ * Licensed under the Apache License, Version 2.0 (the "License");
16+ * you may not use this file except in compliance with the License.
17+ * You may obtain a copy of the License at
18+ *
19+ * http://www.apache.org/licenses/LICENSE-2.0
20+ * -or-
21+ * see COPYING.ASL20 in the source distribution
22+ *
23+ * Unless required by applicable law or agreed to in writing, software
24+ * distributed under the License is distributed on an "AS IS" BASIS,
25+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
26+ * See the License for the specific language governing permissions and
27+ * limitations under the License.
28+ */
29+#include "config.h"
30+#include <stdio.h>
31+#include <stdlib.h>
32+#include <assert.h>
33+#include <string.h>
34+#include <errno.h>
35+#include <unistd.h>
36+#include <grp.h>
37+#include <stdarg.h>
38+#include <sys/resource.h>
39+#include <sys/types.h>
40+#include <sys/stat.h>
41+
42+#include "rsyslog.h"
43+#include "obj.h"
44+#include "srUtils.h"
45+#include "ruleset.h"
46+#include "modules.h"
47+#include "conf.h"
48+#include "queue.h"
49+#include "rsconf.h"
50+#include "cfsysline.h"
51+#include "errmsg.h"
52+#include "action.h"
53+#include "glbl.h"
54+#include "unicode-helper.h"
55+#include "omshell.h"
56+#include "omusrmsg.h"
57+#include "omfwd.h"
58+#include "omfile.h"
59+#include "ompipe.h"
60+#include "omdiscard.h"
61+#include "pmrfc5424.h"
62+#include "pmrfc3164.h"
63+#include "smfile.h"
64+#include "smtradfile.h"
65+#include "smfwd.h"
66+#include "smtradfwd.h"
67+#include "parser.h"
68+#include "outchannel.h"
69+#include "threads.h"
70+#include "datetime.h"
71+#include "parserif.h"
72+#include "modules.h"
73+#include "dirty.h"
74+#include "template.h"
75+
76+extern char* yytext;
77+/* static data */
78+DEFobjStaticHelpers
79+DEFobjCurrIf(ruleset)
80+DEFobjCurrIf(module)
81+DEFobjCurrIf(conf)
82+DEFobjCurrIf(errmsg)
83+DEFobjCurrIf(glbl)
84+DEFobjCurrIf(parser)
85+DEFobjCurrIf(datetime)
86+
87+/* exported static data */
88+rsconf_t *runConf = NULL;/* the currently running config */
89+rsconf_t *loadConf = NULL;/* the config currently being loaded (no concurrent config load supported!) */
90+
91+/* hardcoded standard templates (used for defaults) */
92+static uchar template_DebugFormat[] = "\"Debug line with all properties:\nFROMHOST: '%FROMHOST%', fromhost-ip: '%fromhost-ip%', HOSTNAME: '%HOSTNAME%', PRI: %PRI%,\nsyslogtag '%syslogtag%', programname: '%programname%', APP-NAME: '%APP-NAME%', PROCID: '%PROCID%', MSGID: '%MSGID%',\nTIMESTAMP: '%TIMESTAMP%', STRUCTURED-DATA: '%STRUCTURED-DATA%',\nmsg: '%msg%'\nescaped msg: '%msg:::drop-cc%'\ninputname: %inputname% rawmsg: '%rawmsg%'\n\n\"";
93+static uchar template_SyslogProtocol23Format[] = "\"<%PRI%>1 %TIMESTAMP:::date-rfc3339% %HOSTNAME% %APP-NAME% %PROCID% %MSGID% %STRUCTURED-DATA% %msg%\n\"";
94+static uchar template_TraditionalFileFormat[] = "=RSYSLOG_TraditionalFileFormat";
95+static uchar template_FileFormat[] = "=RSYSLOG_FileFormat";
96+static uchar template_ForwardFormat[] = "=RSYSLOG_ForwardFormat";
97+static uchar template_TraditionalForwardFormat[] = "=RSYSLOG_TraditionalForwardFormat";
98+static uchar template_WallFmt[] = "\"\r\n\7Message from syslogd@%HOSTNAME% at %timegenerated% ...\r\n %syslogtag%%msg%\n\r\"";
99+static uchar template_StdUsrMsgFmt[] = "\" %syslogtag%%msg%\n\r\"";
100+static uchar template_StdDBFmt[] = "\"insert into SystemEvents (Message, Facility, FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values ('%msg%', %syslogfacility%, '%HOSTNAME%', %syslogpriority%, '%timereported:::date-mysql%', '%timegenerated:::date-mysql%', %iut%, '%syslogtag%')\",SQL";
101+static uchar template_StdPgSQLFmt[] = "\"insert into SystemEvents (Message, Facility, FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values ('%msg%', %syslogfacility%, '%HOSTNAME%', %syslogpriority%, '%timereported:::date-pgsql%', '%timegenerated:::date-pgsql%', %iut%, '%syslogtag%')\",STDSQL";
102+static uchar template_spoofadr[] = "\"%fromhost-ip%\"";
103+static uchar template_SysklogdFileFormat[] = "\"%TIMESTAMP% %HOSTNAME% %syslogtag%%msg:::sp-if-no-1st-sp%%msg%\n\"";
104+static uchar template_StdJSONFmt[] = "\"{\\\"message\\\":\\\"%msg:::json%\\\",\\\"fromhost\\\":\\\"%HOSTNAME:::json%\\\",\\\"facility\\\":\\\"%syslogfacility-text%\\\",\\\"priority\\\":\\\"%syslogpriority-text%\\\",\\\"timereported\\\":\\\"%timereported:::date-rfc3339%\\\",\\\"timegenerated\\\":\\\"%timegenerated:::date-rfc3339%\\\"}\"";
105+/* end templates */
106+
107+/* tables for interfacing with the v6 config system (as far as we need to) */
108+static struct cnfparamdescr inppdescr[] = {
109+ { "type", eCmdHdlrString, CNFPARAM_REQUIRED }
110+};
111+static struct cnfparamblk inppblk =
112+ { CNFPARAMBLK_VERSION,
113+ sizeof(inppdescr)/sizeof(struct cnfparamdescr),
114+ inppdescr
115+ };
116+
117+/* forward-definitions */
118+void cnfDoCfsysline(char *ln);
119+
120+/* Standard-Constructor
121+ */
122+BEGINobjConstruct(rsconf) /* be sure to specify the object type also in END macro! */
123+ pThis->globals.bDebugPrintTemplateList = 1;
124+ pThis->globals.bDebugPrintModuleList = 0;
125+ pThis->globals.bDebugPrintCfSysLineHandlerList = 0;
126+ pThis->globals.bLogStatusMsgs = DFLT_bLogStatusMsgs;
127+ pThis->globals.bErrMsgToStderr = 1;
128+ pThis->globals.umask = -1;
129+ pThis->templates.root = NULL;
130+ pThis->templates.last = NULL;
131+ pThis->templates.lastStatic = NULL;
132+ pThis->actions.nbrActions = 0;
133+ CHKiRet(llInit(&pThis->rulesets.llRulesets, rulesetDestructForLinkedList,
134+ rulesetKeyDestruct, strcasecmp));
135+ /* queue params */
136+ pThis->globals.mainQ.iMainMsgQueueSize = 10000;
137+ pThis->globals.mainQ.iMainMsgQHighWtrMark = 8000;
138+ pThis->globals.mainQ.iMainMsgQLowWtrMark = 2000;
139+ pThis->globals.mainQ.iMainMsgQDiscardMark = 9800;
140+ pThis->globals.mainQ.iMainMsgQDiscardSeverity = 8;
141+ pThis->globals.mainQ.iMainMsgQueueNumWorkers = 1;
142+ pThis->globals.mainQ.MainMsgQueType = QUEUETYPE_FIXED_ARRAY;
143+ pThis->globals.mainQ.pszMainMsgQFName = NULL;
144+ pThis->globals.mainQ.iMainMsgQueMaxFileSize = 1024*1024;
145+ pThis->globals.mainQ.iMainMsgQPersistUpdCnt = 0;
146+ pThis->globals.mainQ.bMainMsgQSyncQeueFiles = 0;
147+ pThis->globals.mainQ.iMainMsgQtoQShutdown = 1500;
148+ pThis->globals.mainQ.iMainMsgQtoActShutdown = 1000;
149+ pThis->globals.mainQ.iMainMsgQtoEnq = 2000;
150+ pThis->globals.mainQ.iMainMsgQtoWrkShutdown = 60000;
151+ pThis->globals.mainQ.iMainMsgQWrkMinMsgs = 100;
152+ pThis->globals.mainQ.iMainMsgQDeqSlowdown = 0;
153+ pThis->globals.mainQ.iMainMsgQueMaxDiskSpace = 0;
154+ pThis->globals.mainQ.iMainMsgQueDeqBatchSize = 32;
155+ pThis->globals.mainQ.bMainMsgQSaveOnShutdown = 1;
156+ pThis->globals.mainQ.iMainMsgQueueDeqtWinFromHr = 0;
157+ pThis->globals.mainQ.iMainMsgQueueDeqtWinToHr = 25;
158+ /* end queue params */
159+finalize_it:
160+ENDobjConstruct(rsconf)
161+
162+
163+/* ConstructionFinalizer
164+ */
165+rsRetVal rsconfConstructFinalize(rsconf_t __attribute__((unused)) *pThis)
166+{
167+ DEFiRet;
168+ ISOBJ_TYPE_assert(pThis, rsconf);
169+ RETiRet;
170+}
171+
172+
173+/* call freeCnf() module entry points AND free the module entries themselfes.
174+ */
175+static inline void
176+freeCnf(rsconf_t *pThis)
177+{
178+ cfgmodules_etry_t *etry, *del;
179+ etry = pThis->modules.root;
180+ while(etry != NULL) {
181+ if(etry->pMod->beginCnfLoad != NULL) {
182+ dbgprintf("calling freeCnf(%p) for module '%s'\n",
183+ etry->modCnf, (char*) module.GetName(etry->pMod));
184+ etry->pMod->freeCnf(etry->modCnf);
185+ }
186+ del = etry;
187+ etry = etry->next;
188+ free(del);
189+ }
190+}
191+
192+
193+/* destructor for the rsconf object */
194+BEGINobjDestruct(rsconf) /* be sure to specify the object type also in END and CODESTART macros! */
195+CODESTARTobjDestruct(rsconf)
196+ freeCnf(pThis);
197+ tplDeleteAll(pThis);
198+ free(pThis->globals.mainQ.pszMainMsgQFName);
199+ free(pThis->globals.pszConfDAGFile);
200+ llDestroy(&(pThis->rulesets.llRulesets));
201+ENDobjDestruct(rsconf)
202+
203+
204+/* DebugPrint support for the rsconf object */
205+BEGINobjDebugPrint(rsconf) /* be sure to specify the object type also in END and CODESTART macros! */
206+ cfgmodules_etry_t *modNode;
207+
208+ dbgprintf("configuration object %p\n", pThis);
209+ dbgprintf("Global Settings:\n");
210+ dbgprintf(" bDebugPrintTemplateList.............: %d\n",
211+ pThis->globals.bDebugPrintTemplateList);
212+ dbgprintf(" bDebugPrintModuleList : %d\n",
213+ pThis->globals.bDebugPrintModuleList);
214+ dbgprintf(" bDebugPrintCfSysLineHandlerList.....: %d\n",
215+ pThis->globals.bDebugPrintCfSysLineHandlerList);
216+ dbgprintf(" bLogStatusMsgs : %d\n",
217+ pThis->globals.bLogStatusMsgs);
218+ dbgprintf(" bErrMsgToStderr.....................: %d\n",
219+ pThis->globals.bErrMsgToStderr);
220+ dbgprintf(" drop Msgs with malicious PTR Record : %d\n",
221+ glbl.GetDropMalPTRMsgs());
222+ ruleset.DebugPrintAll(pThis);
223+ dbgprintf("\n");
224+ if(pThis->globals.bDebugPrintTemplateList)
225+ tplPrintList(pThis);
226+ if(pThis->globals.bDebugPrintModuleList)
227+ module.PrintList();
228+ if(pThis->globals.bDebugPrintCfSysLineHandlerList)
229+ dbgPrintCfSysLineHandlers();
230+ // TODO: The following code needs to be "streamlined", so far just moved over...
231+ dbgprintf("Main queue size %d messages.\n", pThis->globals.mainQ.iMainMsgQueueSize);
232+ dbgprintf("Main queue worker threads: %d, wThread shutdown: %d, Perists every %d updates.\n",
233+ pThis->globals.mainQ.iMainMsgQueueNumWorkers,
234+ pThis->globals.mainQ.iMainMsgQtoWrkShutdown, pThis->globals.mainQ.iMainMsgQPersistUpdCnt);
235+ dbgprintf("Main queue timeouts: shutdown: %d, action completion shutdown: %d, enq: %d\n",
236+ pThis->globals.mainQ.iMainMsgQtoQShutdown,
237+ pThis->globals.mainQ.iMainMsgQtoActShutdown, pThis->globals.mainQ.iMainMsgQtoEnq);
238+ dbgprintf("Main queue watermarks: high: %d, low: %d, discard: %d, discard-severity: %d\n",
239+ pThis->globals.mainQ.iMainMsgQHighWtrMark, pThis->globals.mainQ.iMainMsgQLowWtrMark,
240+ pThis->globals.mainQ.iMainMsgQDiscardMark, pThis->globals.mainQ.iMainMsgQDiscardSeverity);
241+ dbgprintf("Main queue save on shutdown %d, max disk space allowed %lld\n",
242+ pThis->globals.mainQ.bMainMsgQSaveOnShutdown, pThis->globals.mainQ.iMainMsgQueMaxDiskSpace);
243+ /* TODO: add
244+ iActionRetryCount = 0;
245+ iActionRetryInterval = 30000;
246+ static int iMainMsgQtoWrkMinMsgs = 100;
247+ static int iMainMsgQbSaveOnShutdown = 1;
248+ iMainMsgQueMaxDiskSpace = 0;
249+ setQPROP(qqueueSetiMinMsgsPerWrkr, "$MainMsgQueueWorkerThreadMinimumMessages", 100);
250+ setQPROP(qqueueSetbSaveOnShutdown, "$MainMsgQueueSaveOnShutdown", 1);
251+ */
252+ dbgprintf("Work Directory: '%s'.\n", glbl.GetWorkDir());
253+ ochPrintList();
254+ dbgprintf("Modules used in this configuration:\n");
255+ for(modNode = pThis->modules.root ; modNode != NULL ; modNode = modNode->next) {
256+ dbgprintf(" %s\n", module.GetName(modNode->pMod));
257+ }
258+CODESTARTobjDebugPrint(rsconf)
259+ENDobjDebugPrint(rsconf)
260+
261+
262+/* This function returns the current date in different
263+ * variants. It is used to construct the $NOW series of
264+ * system properties. The returned buffer must be freed
265+ * by the caller when no longer needed. If the function
266+ * can not allocate memory, it returns a NULL pointer.
267+ * TODO: this was taken from msg.c and we should consolidate it with the code
268+ * there. This is especially important when we increase the number of system
269+ * variables (what we definitely want to do).
270+ */
271+typedef enum ENOWType { NOW_NOW, NOW_YEAR, NOW_MONTH, NOW_DAY, NOW_HOUR, NOW_MINUTE } eNOWType;
272+static rsRetVal
273+getNOW(eNOWType eNow, es_str_t **estr)
274+{
275+ DEFiRet;
276+ uchar szBuf[16];
277+ struct syslogTime t;
278+ es_size_t len;
279+
280+ datetime.getCurrTime(&t, NULL);
281+ switch(eNow) {
282+ case NOW_NOW:
283+ len = snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar),
284+ "%4.4d-%2.2d-%2.2d", t.year, t.month, t.day);
285+ break;
286+ case NOW_YEAR:
287+ len = snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%4.4d", t.year);
288+ break;
289+ case NOW_MONTH:
290+ len = snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%2.2d", t.month);
291+ break;
292+ case NOW_DAY:
293+ len = snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%2.2d", t.day);
294+ break;
295+ case NOW_HOUR:
296+ len = snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%2.2d", t.hour);
297+ break;
298+ case NOW_MINUTE:
299+ len = snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%2.2d", t.minute);
300+ break;
301+ default:
302+ len = snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "*invld eNow*");
303+ break;
304+ }
305+
306+ /* now create a string object out of it and hand that over to the var */
307+ *estr = es_newStrFromCStr((char*)szBuf, len);
308+
309+ RETiRet;
310+}
311+
312+
313+
314+static inline es_str_t *
315+getSysVar(char *name)
316+{
317+ es_str_t *estr = NULL;
318+ rsRetVal iRet = RS_RET_OK;
319+
320+ if(!strcmp(name, "now")) {
321+ CHKiRet(getNOW(NOW_NOW, &estr));
322+ } else if(!strcmp(name, "year")) {
323+ CHKiRet(getNOW(NOW_YEAR, &estr));
324+ } else if(!strcmp(name, "month")) {
325+ CHKiRet(getNOW(NOW_MONTH, &estr));
326+ } else if(!strcmp(name, "day")) {
327+ CHKiRet(getNOW(NOW_DAY, &estr));
328+ } else if(!strcmp(name, "hour")) {
329+ CHKiRet(getNOW(NOW_HOUR, &estr));
330+ } else if(!strcmp(name, "minute")) {
331+ CHKiRet(getNOW(NOW_MINUTE, &estr));
332+ } else if(!strcmp(name, "myhostname")) {
333+ char *hn = (char*)glbl.GetLocalHostName();
334+ estr = es_newStrFromCStr(hn, strlen(hn));
335+ } else {
336+ ABORT_FINALIZE(RS_RET_SYSVAR_NOT_FOUND);
337+ }
338+finalize_it:
339+ if(iRet != RS_RET_OK) {
340+ dbgprintf("getSysVar error iRet %d\n", iRet);
341+ if(estr == NULL)
342+ estr = es_newStrFromCStr("*ERROR*", sizeof("*ERROR*") - 1);
343+ }
344+ return estr;
345+}
346+
347+
348+/* Process input() objects */
349+rsRetVal
350+inputProcessCnf(struct cnfobj *o)
351+{
352+ struct cnfparamvals *pvals;
353+ modInfo_t *pMod;
354+ uchar *cnfModName = NULL;
355+ int typeIdx;
356+ DEFiRet;
357+
358+ pvals = nvlstGetParams(o->nvlst, &inppblk, NULL);
359+ if(pvals == NULL) {
360+ ABORT_FINALIZE(RS_RET_CONFIG_ERROR);
361+ }
362+ DBGPRINTF("input param blk after inputProcessCnf:\n");
363+ cnfparamsPrint(&inppblk, pvals);
364+ typeIdx = cnfparamGetIdx(&inppblk, "type");
365+ cnfModName = (uchar*)es_str2cstr(pvals[typeIdx].val.d.estr, NULL);
366+ if((pMod = module.FindWithCnfName(loadConf, cnfModName, eMOD_IN)) == NULL) {
367+ errmsg.LogError(0, RS_RET_MOD_UNKNOWN, "input module name '%s' is unknown", cnfModName);
368+ ABORT_FINALIZE(RS_RET_MOD_UNKNOWN);
369+ }
370+ if(pMod->mod.im.newInpInst == NULL) {
371+ errmsg.LogError(0, RS_RET_MOD_NO_INPUT_STMT,
372+ "input module '%s' does not support input() statement", cnfModName);
373+ ABORT_FINALIZE(RS_RET_MOD_NO_INPUT_STMT);
374+ }
375+ CHKiRet(pMod->mod.im.newInpInst(o->nvlst));
376+finalize_it:
377+ free(cnfModName);
378+ cnfparamvalsDestruct(pvals, &inppblk);
379+ RETiRet;
380+}
381+
382+/*------------------------------ interface to flex/bison parser ------------------------------*/
383+extern int yylineno;
384+
385+void
386+parser_errmsg(char *fmt, ...)
387+{
388+ va_list ap;
389+ char errBuf[1024];
390+
391+ va_start(ap, fmt);
392+ if(vsnprintf(errBuf, sizeof(errBuf), fmt, ap) == sizeof(errBuf))
393+ errBuf[sizeof(errBuf)-1] = '\0';
394+ errmsg.LogError(0, RS_RET_CONF_PARSE_ERROR,
395+ "error during parsing file %s, on or before line %d: %s",
396+ cnfcurrfn, yylineno, errBuf);
397+ va_end(ap);
398+}
399+
400+int
401+yyerror(char *s)
402+{
403+ parser_errmsg("%s on token '%s'", s, yytext);
404+ return 0;
405+}
406+void cnfDoObj(struct cnfobj *o)
407+{
408+ int bChkUnuse = 1;
409+
410+ dbgprintf("cnf:global:obj: ");
411+ cnfobjPrint(o);
412+ switch(o->objType) {
413+ case CNFOBJ_GLOBAL:
414+ glblProcessCnf(o);
415+ break;
416+ case CNFOBJ_MODULE:
417+ modulesProcessCnf(o);
418+ break;
419+ case CNFOBJ_INPUT:
420+ inputProcessCnf(o);
421+ break;
422+ case CNFOBJ_TPL:
423+ if(tplProcessCnf(o) != RS_RET_OK)
424+ parser_errmsg("error processing template object");
425+ break;
426+ case CNFOBJ_RULESET:
427+ rulesetProcessCnf(o);
428+ break;
429+ case CNFOBJ_PROPERTY:
430+ case CNFOBJ_CONSTANT:
431+ /* these types are processed at a later stage */
432+ bChkUnuse = 0;
433+ break;
434+ default:
435+ dbgprintf("cnfDoObj program error: unexpected object type %u\n",
436+ o->objType);
437+ break;
438+ }
439+ if(bChkUnuse)
440+ nvlstChkUnused(o->nvlst);
441+ cnfobjDestruct(o);
442+}
443+
444+void cnfDoScript(struct cnfstmt *script)
445+{
446+ dbgprintf("cnf:global:script\n");
447+ ruleset.AddScript(ruleset.GetCurrent(loadConf), script);
448+}
449+
450+void cnfDoCfsysline(char *ln)
451+{
452+ DBGPRINTF("cnf:global:cfsysline: %s\n", ln);
453+ /* the legacy system needs the "$" stripped */
454+ conf.cfsysline((uchar*) ln+1);
455+ free(ln);
456+}
457+
458+void cnfDoBSDTag(char *ln)
459+{
460+ DBGPRINTF("cnf:global:BSD tag: %s\n", ln);
461+ errmsg.LogError(0, RS_RET_BSD_BLOCKS_UNSUPPORTED,
462+ "BSD-style blocks are no longer supported in rsyslog, "
463+ "see http://www.rsyslog.com/g/BSD for details and a "
464+ "solution (Block '%s')", ln);
465+ free(ln);
466+}
467+
468+void cnfDoBSDHost(char *ln)
469+{
470+ DBGPRINTF("cnf:global:BSD host: %s\n", ln);
471+ errmsg.LogError(0, RS_RET_BSD_BLOCKS_UNSUPPORTED,
472+ "BSD-style blocks are no longer supported in rsyslog, "
473+ "see http://www.rsyslog.com/g/BSD for details and a "
474+ "solution (Block '%s')", ln);
475+ free(ln);
476+}
477+
478+es_str_t*
479+cnfGetVar(char *name, void *usrptr)
480+{
481+ es_str_t *estr;
482+ if(name[0] == '$') {
483+ if(name[1] == '$')
484+ estr = getSysVar(name+2);
485+ else if(name[1] == '!')
486+ estr = msgGetCEEVarNew((msg_t*) usrptr, name+2);
487+ else
488+ estr = msgGetMsgVarNew((msg_t*) usrptr, (uchar*)name+1);
489+ } else { /* if this happens, we have a program logic error */
490+ estr = es_newStrFromCStr("err: var must start with $",
491+ strlen("err: var must start with $"));
492+ }
493+ if(Debug) {
494+ char *s;
495+ s = es_str2cstr(estr, NULL);
496+ dbgprintf("rainerscript: var '%s': '%s'\n", name, s);
497+ free(s);
498+ }
499+ return estr;
500+}
501+/*------------------------------ end interface to flex/bison parser ------------------------------*/
502+
503+
504+
505+/* drop to specified group
506+ * if something goes wrong, the function never returns
507+ * Note that such an abort can cause damage to on-disk structures, so we should
508+ * re-design the "interface" in the long term. -- rgerhards, 2008-11-26
509+ */
510+static void doDropPrivGid(int iGid)
511+{
512+ int res;
513+ uchar szBuf[1024];
514+
515+ res = setgroups(0, NULL); /* remove all supplementary group IDs */
516+ if(res) {
517+ perror("could not remove supplemental group IDs");
518+ exit(1);
519+ }
520+ DBGPRINTF("setgroups(0, NULL): %d\n", res);
521+ res = setgid(iGid);
522+ if(res) {
523+ /* if we can not set the userid, this is fatal, so let's unconditionally abort */
524+ perror("could not set requested group id");
525+ exit(1);
526+ }
527+ DBGPRINTF("setgid(%d): %d\n", iGid, res);
528+ snprintf((char*)szBuf, sizeof(szBuf)/sizeof(uchar), "rsyslogd's groupid changed to %d", iGid);
529+ logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, szBuf, 0);
530+}
531+
532+
533+/* drop to specified user
534+ * if something goes wrong, the function never returns
535+ * Note that such an abort can cause damage to on-disk structures, so we should
536+ * re-design the "interface" in the long term. -- rgerhards, 2008-11-19
537+ */
538+static void doDropPrivUid(int iUid)
539+{
540+ int res;
541+ uchar szBuf[1024];
542+
543+ res = setuid(iUid);
544+ if(res) {
545+ /* if we can not set the userid, this is fatal, so let's unconditionally abort */
546+ perror("could not set requested userid");
547+ exit(1);
548+ }
549+ DBGPRINTF("setuid(%d): %d\n", iUid, res);
550+ snprintf((char*)szBuf, sizeof(szBuf)/sizeof(uchar), "rsyslogd's userid changed to %d", iUid);
551+ logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, szBuf, 0);
552+}
553+
554+
555+
556+/* drop privileges. This will drop to the configured privileges, if
557+ * set by the user. After this method has been executed, the previous
558+ * privileges can no be re-gained.
559+ */
560+static inline rsRetVal
561+dropPrivileges(rsconf_t *cnf)
562+{
563+ DEFiRet;
564+
565+ /* If instructed to do so, we now drop privileges. Note that this is not 100% secure,
566+ * because outputs are already running at this time. However, we can implement
567+ * dropping of privileges rather quickly and it will work in many cases. While it is not
568+ * the ultimate solution, the current one is still much better than not being able to
569+ * drop privileges at all. Doing it correctly, requires a change in architecture, which
570+ * we should do over time. TODO -- rgerhards, 2008-11-19
571+ */
572+ if(cnf->globals.gidDropPriv != 0) {
573+ doDropPrivGid(ourConf->globals.gidDropPriv);
574+ DBGPRINTF("group privileges have been dropped to gid %u\n", (unsigned)
575+ ourConf->globals.gidDropPriv);
576+ }
577+
578+ if(cnf->globals.uidDropPriv != 0) {
579+ doDropPrivUid(ourConf->globals.uidDropPriv);
580+ DBGPRINTF("user privileges have been dropped to uid %u\n", (unsigned)
581+ ourConf->globals.uidDropPriv);
582+ }
583+
584+ RETiRet;
585+}
586+
587+
588+/* tell the rsysog core (including ourselfs) that the config load is done and
589+ * we need to prepare to move over to activate mode.
590+ */
591+static inline void
592+tellCoreConfigLoadDone(void)
593+{
594+ glblDoneLoadCnf();
595+}
596+
597+
598+/* Tell input modules that the config parsing stage is over. */
599+static rsRetVal
600+tellModulesConfigLoadDone(void)
601+{
602+ cfgmodules_etry_t *node;
603+
604+ BEGINfunc
605+ DBGPRINTF("telling modules that config load for %p is done\n", loadConf);
606+ node = module.GetNxtCnfType(loadConf, NULL, eMOD_ANY);
607+ while(node != NULL) {
608+ if(node->pMod->beginCnfLoad != NULL)
609+ node->pMod->endCnfLoad(node->modCnf);
610+ node = module.GetNxtCnfType(runConf, node, eMOD_IN);
611+ }
612+
613+ ENDfunc
614+ return RS_RET_OK; /* intentional: we do not care about module errors */
615+}
616+
617+
618+/* Tell input modules to verify config object */
619+static rsRetVal
620+tellModulesCheckConfig(void)
621+{
622+ cfgmodules_etry_t *node;
623+ rsRetVal localRet;
624+
625+ BEGINfunc
626+ DBGPRINTF("telling modules to check config %p\n", loadConf);
627+ node = module.GetNxtCnfType(loadConf, NULL, eMOD_ANY);
628+ while(node != NULL) {
629+ if(node->pMod->beginCnfLoad != NULL) {
630+ localRet = node->pMod->checkCnf(node->modCnf);
631+ DBGPRINTF("module %s tells us config can %sbe activated\n",
632+ node->pMod->pszName, (localRet == RS_RET_OK) ? "" : "NOT ");
633+ if(localRet == RS_RET_OK) {
634+ node->canActivate = 1;
635+ } else {
636+ node->canActivate = 0;
637+ }
638+ }
639+ node = module.GetNxtCnfType(runConf, node, eMOD_IN);
640+ }
641+
642+ ENDfunc
643+ return RS_RET_OK; /* intentional: we do not care about module errors */
644+}
645+
646+
647+/* Tell modules to activate current running config (pre privilege drop) */
648+static rsRetVal
649+tellModulesActivateConfigPrePrivDrop(void)
650+{
651+ cfgmodules_etry_t *node;
652+ rsRetVal localRet;
653+
654+ BEGINfunc
655+ DBGPRINTF("telling modules to activate config (before dropping privs) %p\n", runConf);
656+ node = module.GetNxtCnfType(runConf, NULL, eMOD_ANY);
657+ while(node != NULL) {
658+ if( node->pMod->beginCnfLoad != NULL
659+ && node->pMod->activateCnfPrePrivDrop != NULL
660+ && node->canActivate) {
661+ DBGPRINTF("pre priv drop activating config %p for module %s\n",
662+ runConf, node->pMod->pszName);
663+ localRet = node->pMod->activateCnfPrePrivDrop(node->modCnf);
664+ if(localRet != RS_RET_OK) {
665+ errmsg.LogError(0, localRet, "activation of module %s failed",
666+ node->pMod->pszName);
667+ node->canActivate = 0; /* in a sense, could not activate... */
668+ }
669+ }
670+ node = module.GetNxtCnfType(runConf, node, eMOD_IN);
671+ }
672+
673+ ENDfunc
674+ return RS_RET_OK; /* intentional: we do not care about module errors */
675+}
676+
677+
678+/* Tell modules to activate current running config */
679+static rsRetVal
680+tellModulesActivateConfig(void)
681+{
682+ cfgmodules_etry_t *node;
683+ rsRetVal localRet;
684+
685+ BEGINfunc
686+ DBGPRINTF("telling modules to activate config %p\n", runConf);
687+ node = module.GetNxtCnfType(runConf, NULL, eMOD_ANY);
688+ while(node != NULL) {
689+ if(node->pMod->beginCnfLoad != NULL && node->canActivate) {
690+ DBGPRINTF("activating config %p for module %s\n",
691+ runConf, node->pMod->pszName);
692+ localRet = node->pMod->activateCnf(node->modCnf);
693+ if(localRet != RS_RET_OK) {
694+ errmsg.LogError(0, localRet, "activation of module %s failed",
695+ node->pMod->pszName);
696+ node->canActivate = 0; /* in a sense, could not activate... */
697+ }
698+ }
699+ node = module.GetNxtCnfType(runConf, node, eMOD_IN);
700+ }
701+
702+ ENDfunc
703+ return RS_RET_OK; /* intentional: we do not care about module errors */
704+}
705+
706+
707+/* Actually run the input modules. This happens after privileges are dropped,
708+ * if that is requested.
709+ */
710+static rsRetVal
711+runInputModules(void)
712+{
713+ cfgmodules_etry_t *node;
714+ int bNeedsCancel;
715+
716+ BEGINfunc
717+ node = module.GetNxtCnfType(runConf, NULL, eMOD_IN);
718+ while(node != NULL) {
719+ if(node->canRun) {
720+ bNeedsCancel = (node->pMod->isCompatibleWithFeature(sFEATURENonCancelInputTermination) == RS_RET_OK) ?
721+ 0 : 1;
722+ DBGPRINTF("running module %s with config %p, term mode: %s\n", node->pMod->pszName, node,
723+ bNeedsCancel ? "cancel" : "cooperative/SIGTTIN");
724+ thrdCreate(node->pMod->mod.im.runInput, node->pMod->mod.im.afterRun, bNeedsCancel,
725+ (node->pMod->cnfName == NULL) ? node->pMod->pszName : node->pMod->cnfName);
726+ }
727+ node = module.GetNxtCnfType(runConf, node, eMOD_IN);
728+ }
729+
730+ ENDfunc
731+ return RS_RET_OK; /* intentional: we do not care about module errors */
732+}
733+
734+
735+/* Make the modules check if they are ready to start.
736+ */
737+static rsRetVal
738+startInputModules(void)
739+{
740+ DEFiRet;
741+ cfgmodules_etry_t *node;
742+
743+ node = module.GetNxtCnfType(runConf, NULL, eMOD_IN);
744+ while(node != NULL) {
745+ if(node->canActivate) {
746+ iRet = node->pMod->mod.im.willRun();
747+ node->canRun = (iRet == RS_RET_OK);
748+ if(!node->canRun) {
749+ DBGPRINTF("module %s will not run, iRet %d\n", node->pMod->pszName, iRet);
750+ }
751+ } else {
752+ node->canRun = 0;
753+ }
754+ node = module.GetNxtCnfType(runConf, node, eMOD_IN);
755+ }
756+
757+ ENDfunc
758+ return RS_RET_OK; /* intentional: we do not care about module errors */
759+}
760+
761+
762+/* activate the main queue */
763+static inline rsRetVal
764+activateMainQueue()
765+{
766+ DEFiRet;
767+ /* create message queue */
768+ CHKiRet_Hdlr(createMainQueue(&pMsgQueue, UCHAR_CONSTANT("main Q"), NULL)) {
769+ /* no queue is fatal, we need to give up in that case... */
770+ fprintf(stderr, "fatal error %d: could not create message queue - rsyslogd can not run!\n", iRet);
771+ FINALIZE;
772+ }
773+
774+ bHaveMainQueue = (ourConf->globals.mainQ.MainMsgQueType == QUEUETYPE_DIRECT) ? 0 : 1;
775+ DBGPRINTF("Main processing queue is initialized and running\n");
776+finalize_it:
777+ RETiRet;
778+}
779+
780+
781+/* set the processes umask (upon configuration request) */
782+static inline rsRetVal
783+setUmask(int iUmask)
784+{
785+ if(iUmask != -1) {
786+ umask(iUmask);
787+ DBGPRINTF("umask set to 0%3.3o.\n", iUmask);
788+ }
789+
790+ return RS_RET_OK;
791+}
792+
793+
794+/* Activate an already-loaded configuration. The configuration will become
795+ * the new running conf (if successful). Note that in theory this method may
796+ * be called when there already is a running conf. In practice, the current
797+ * version of rsyslog does not support this. Future versions probably will.
798+ * Begun 2011-04-20, rgerhards
799+ */
800+rsRetVal
801+activate(rsconf_t *cnf)
802+{
803+ DEFiRet;
804+
805+ /* at this point, we "switch" over to the running conf */
806+ runConf = cnf;
807+# if 0 /* currently the DAG is not supported -- code missing! */
808+ /* TODO: re-enable this functionality some time later! */
809+ /* check if we need to generate a config DAG and, if so, do that */
810+ if(ourConf->globals.pszConfDAGFile != NULL)
811+ generateConfigDAG(ourConf->globals.pszConfDAGFile);
812+# endif
813+ setUmask(cnf->globals.umask);
814+
815+ /* the output part and the queue is now ready to run. So it is a good time
816+ * to initialize the inputs. Please note that the net code above should be
817+ * shuffled to down here once we have everything in input modules.
818+ * rgerhards, 2007-12-14
819+ * NOTE: as of 2009-06-29, the input modules are initialized, but not yet run.
820+ * Keep in mind. though, that the outputs already run if the queue was
821+ * persisted to disk. -- rgerhards
822+ */
823+ tellModulesActivateConfigPrePrivDrop();
824+
825+ CHKiRet(dropPrivileges(cnf));
826+
827+ tellModulesActivateConfig();
828+ startInputModules();
829+ CHKiRet(activateActions());
830+ CHKiRet(activateMainQueue());
831+ /* finally let the inputs run... */
832+ runInputModules();
833+
834+ dbgprintf("configuration %p activated\n", cnf);
835+
836+finalize_it:
837+ RETiRet;
838+}
839+
840+
841+/* -------------------- some legacy config handlers --------------------
842+ * TODO: move to conf.c?
843+ */
844+
845+/* legacy config system: set the action resume interval */
846+static rsRetVal setActionResumeInterval(void __attribute__((unused)) *pVal, int iNewVal)
847+{
848+ return actionSetGlobalResumeInterval(iNewVal);
849+}
850+
851+
852+/* Switch the default ruleset (that, what servcies bind to if nothing specific
853+ * is specified).
854+ * rgerhards, 2009-06-12
855+ */
856+static rsRetVal
857+setDefaultRuleset(void __attribute__((unused)) *pVal, uchar *pszName)
858+{
859+ DEFiRet;
860+
861+ CHKiRet(ruleset.SetDefaultRuleset(ourConf, pszName));
862+
863+finalize_it:
864+ free(pszName); /* no longer needed */
865+ RETiRet;
866+}
867+
868+
869+/* Switch to either an already existing rule set or start a new one. The
870+ * named rule set becomes the new "current" rule set (what means that new
871+ * actions are added to it).
872+ * rgerhards, 2009-06-12
873+ */
874+static rsRetVal
875+setCurrRuleset(void __attribute__((unused)) *pVal, uchar *pszName)
876+{
877+ ruleset_t *pRuleset;
878+ rsRetVal localRet;
879+ DEFiRet;
880+
881+ localRet = ruleset.SetCurrRuleset(ourConf, pszName);
882+
883+ if(localRet == RS_RET_NOT_FOUND) {
884+ DBGPRINTF("begin new current rule set '%s'\n", pszName);
885+ CHKiRet(ruleset.Construct(&pRuleset));
886+ CHKiRet(ruleset.SetName(pRuleset, pszName));
887+ CHKiRet(ruleset.ConstructFinalize(ourConf, pRuleset));
888+ rulesetSetCurrRulesetPtr(pRuleset);
889+ } else {
890+ ABORT_FINALIZE(localRet);
891+ }
892+
893+finalize_it:
894+ free(pszName); /* no longer needed */
895+ RETiRet;
896+}
897+
898+
899+/* set the main message queue mode
900+ * rgerhards, 2008-01-03
901+ */
902+static rsRetVal setMainMsgQueType(void __attribute__((unused)) *pVal, uchar *pszType)
903+{
904+ DEFiRet;
905+
906+ if (!strcasecmp((char *) pszType, "fixedarray")) {
907+ loadConf->globals.mainQ.MainMsgQueType = QUEUETYPE_FIXED_ARRAY;
908+ DBGPRINTF("main message queue type set to FIXED_ARRAY\n");
909+ } else if (!strcasecmp((char *) pszType, "linkedlist")) {
910+ loadConf->globals.mainQ.MainMsgQueType = QUEUETYPE_LINKEDLIST;
911+ DBGPRINTF("main message queue type set to LINKEDLIST\n");
912+ } else if (!strcasecmp((char *) pszType, "disk")) {
913+ loadConf->globals.mainQ.MainMsgQueType = QUEUETYPE_DISK;
914+ DBGPRINTF("main message queue type set to DISK\n");
915+ } else if (!strcasecmp((char *) pszType, "direct")) {
916+ loadConf->globals.mainQ.MainMsgQueType = QUEUETYPE_DIRECT;
917+ DBGPRINTF("main message queue type set to DIRECT (no queueing at all)\n");
918+ } else {
919+ errmsg.LogError(0, RS_RET_INVALID_PARAMS, "unknown mainmessagequeuetype parameter: %s", (char *) pszType);
920+ iRet = RS_RET_INVALID_PARAMS;
921+ }
922+ free(pszType); /* no longer needed */
923+
924+ RETiRet;
925+}
926+
927+
928+/* -------------------- end legacy config handlers -------------------- */
929+
930+
931+/* set the processes max number ob files (upon configuration request)
932+ * 2009-04-14 rgerhards
933+ */
934+static rsRetVal setMaxFiles(void __attribute__((unused)) *pVal, int iFiles)
935+{
936+// TODO this must use a local var, then carry out action during activate!
937+ struct rlimit maxFiles;
938+ char errStr[1024];
939+ DEFiRet;
940+
941+ maxFiles.rlim_cur = iFiles;
942+ maxFiles.rlim_max = iFiles;
943+
944+ if(setrlimit(RLIMIT_NOFILE, &maxFiles) < 0) {
945+ /* NOTE: under valgrind, we seem to be unable to extend the size! */
946+ rs_strerror_r(errno, errStr, sizeof(errStr));
947+ errmsg.LogError(0, RS_RET_ERR_RLIM_NOFILE, "could not set process file limit to %d: %s [kernel max %ld]",
948+ iFiles, errStr, (long) maxFiles.rlim_max);
949+ ABORT_FINALIZE(RS_RET_ERR_RLIM_NOFILE);
950+ }
951+#ifdef USE_UNLIMITED_SELECT
952+ glbl.SetFdSetSize(howmany(iFiles, __NFDBITS) * sizeof (fd_mask));
953+#endif
954+ DBGPRINTF("Max number of files set to %d [kernel max %ld].\n", iFiles, (long) maxFiles.rlim_max);
955+
956+finalize_it:
957+ RETiRet;
958+}
959+
960+
961+/* legacy config system: reset config variables to default values. */
962+static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
963+{
964+ loadConf->globals.bLogStatusMsgs = DFLT_bLogStatusMsgs;
965+ loadConf->globals.bDebugPrintTemplateList = 1;
966+ loadConf->globals.bDebugPrintCfSysLineHandlerList = 1;
967+ loadConf->globals.bDebugPrintModuleList = 1;
968+ loadConf->globals.bAbortOnUncleanConfig = 0;
969+ loadConf->globals.bReduceRepeatMsgs = 0;
970+ free(loadConf->globals.mainQ.pszMainMsgQFName);
971+ loadConf->globals.mainQ.pszMainMsgQFName = NULL;
972+ loadConf->globals.mainQ.iMainMsgQueueSize = 10000;
973+ loadConf->globals.mainQ.iMainMsgQHighWtrMark = 8000;
974+ loadConf->globals.mainQ.iMainMsgQLowWtrMark = 2000;
975+ loadConf->globals.mainQ.iMainMsgQDiscardMark = 9800;
976+ loadConf->globals.mainQ.iMainMsgQDiscardSeverity = 8;
977+ loadConf->globals.mainQ.iMainMsgQueMaxFileSize = 1024 * 1024;
978+ loadConf->globals.mainQ.iMainMsgQueueNumWorkers = 1;
979+ loadConf->globals.mainQ.iMainMsgQPersistUpdCnt = 0;
980+ loadConf->globals.mainQ.bMainMsgQSyncQeueFiles = 0;
981+ loadConf->globals.mainQ.iMainMsgQtoQShutdown = 1500;
982+ loadConf->globals.mainQ.iMainMsgQtoActShutdown = 1000;
983+ loadConf->globals.mainQ.iMainMsgQtoEnq = 2000;
984+ loadConf->globals.mainQ.iMainMsgQtoWrkShutdown = 60000;
985+ loadConf->globals.mainQ.iMainMsgQWrkMinMsgs = 100;
986+ loadConf->globals.mainQ.iMainMsgQDeqSlowdown = 0;
987+ loadConf->globals.mainQ.bMainMsgQSaveOnShutdown = 1;
988+ loadConf->globals.mainQ.MainMsgQueType = QUEUETYPE_FIXED_ARRAY;
989+ loadConf->globals.mainQ.iMainMsgQueMaxDiskSpace = 0;
990+ loadConf->globals.mainQ.iMainMsgQueDeqBatchSize = 32;
991+
992+ return RS_RET_OK;
993+}
994+
995+
996+/* legacy config system: set the action resume interval */
997+static rsRetVal
998+setModDir(void __attribute__((unused)) *pVal, uchar* pszNewVal)
999+{
1000+ DEFiRet;
1001+ iRet = module.SetModDir(pszNewVal);
1002+ free(pszNewVal);
1003+ RETiRet;
1004+}
1005+
1006+
1007+/* "load" a build in module and register it for the current load config */
1008+static rsRetVal
1009+regBuildInModule(rsRetVal (*modInit)(), uchar *name, void *pModHdlr)
1010+{
1011+ cfgmodules_etry_t *pNew;
1012+ cfgmodules_etry_t *pLast;
1013+ modInfo_t *pMod;
1014+ DEFiRet;
1015+ CHKiRet(module.doModInit(modInit, name, pModHdlr, &pMod));
1016+ readyModForCnf(pMod, &pNew, &pLast);
1017+ addModToCnfList(pNew, pLast);
1018+finalize_it:
1019+ RETiRet;
1020+}
1021+
1022+
1023+/* load build-in modules
1024+ * very first version begun on 2007-07-23 by rgerhards
1025+ */
1026+static rsRetVal
1027+loadBuildInModules()
1028+{
1029+ DEFiRet;
1030+
1031+ CHKiRet(regBuildInModule(modInitFile, UCHAR_CONSTANT("builtin:omfile"), NULL));
1032+ CHKiRet(regBuildInModule(modInitPipe, UCHAR_CONSTANT("builtin:ompipe"), NULL));
1033+ CHKiRet(regBuildInModule(modInitShell, UCHAR_CONSTANT("builtin-shell"), NULL));
1034+ CHKiRet(regBuildInModule(modInitDiscard, UCHAR_CONSTANT("builtin:omdiscard"), NULL));
1035+# ifdef SYSLOG_INET
1036+ CHKiRet(regBuildInModule(modInitFwd, UCHAR_CONSTANT("builtin:omfwd"), NULL));
1037+# endif
1038+
1039+ /* dirty, but this must be for the time being: the usrmsg module must always be
1040+ * loaded as last module. This is because it processes any type of action selector.
1041+ * If we load it before other modules, these others will never have a chance of
1042+ * working with the config file. We may change that implementation so that a user name
1043+ * must start with an alnum, that would definitely help (but would it break backwards
1044+ * compatibility?). * rgerhards, 2007-07-23
1045+ * User names now must begin with:
1046+ * [a-zA-Z0-9_.]
1047+ */
1048+ CHKiRet(regBuildInModule(modInitUsrMsg, (uchar*) "builtin:omusrmsg", NULL));
1049+
1050+ /* load build-in parser modules */
1051+ CHKiRet(regBuildInModule(modInitpmrfc5424, UCHAR_CONSTANT("builtin:pmrfc5424"), NULL));
1052+ CHKiRet(regBuildInModule(modInitpmrfc3164, UCHAR_CONSTANT("builtin:pmrfc3164"), NULL));
1053+
1054+ /* and set default parser modules. Order is *very* important, legacy
1055+ * (3164) parser needs to go last! */
1056+ CHKiRet(parser.AddDfltParser(UCHAR_CONSTANT("rsyslog.rfc5424")));
1057+ CHKiRet(parser.AddDfltParser(UCHAR_CONSTANT("rsyslog.rfc3164")));
1058+
1059+ /* load build-in strgen modules */
1060+ CHKiRet(regBuildInModule(modInitsmfile, UCHAR_CONSTANT("builtin:smfile"), NULL));
1061+ CHKiRet(regBuildInModule(modInitsmtradfile, UCHAR_CONSTANT("builtin:smtradfile"), NULL));
1062+ CHKiRet(regBuildInModule(modInitsmfwd, UCHAR_CONSTANT("builtin:smfwd"), NULL));
1063+ CHKiRet(regBuildInModule(modInitsmtradfwd, UCHAR_CONSTANT("builtin:smtradfwd"), NULL));
1064+
1065+finalize_it:
1066+ if(iRet != RS_RET_OK) {
1067+ /* we need to do fprintf, as we do not yet have an error reporting system
1068+ * in place.
1069+ */
1070+ fprintf(stderr, "fatal error: could not activate built-in modules. Error code %d.\n",
1071+ iRet);
1072+ }
1073+ RETiRet;
1074+}
1075+
1076+
1077+/* intialize the legacy config system */
1078+static inline rsRetVal
1079+initLegacyConf(void)
1080+{
1081+ DEFiRet;
1082+ uchar *pTmp;
1083+ ruleset_t *pRuleset;
1084+
1085+ DBGPRINTF("doing legacy config system init\n");
1086+ /* construct the default ruleset */
1087+ ruleset.Construct(&pRuleset);
1088+ ruleset.SetName(pRuleset, UCHAR_CONSTANT("RSYSLOG_DefaultRuleset"));
1089+ ruleset.ConstructFinalize(loadConf, pRuleset);
1090+ rulesetSetCurrRulesetPtr(pRuleset);
1091+
1092+ /* now register config handlers */
1093+ CHKiRet(regCfSysLineHdlr((uchar *)"sleep", 0, eCmdHdlrGoneAway,
1094+ NULL, NULL, NULL));
1095+ CHKiRet(regCfSysLineHdlr((uchar *)"logrsyslogstatusmessages", 0, eCmdHdlrBinary,
1096+ NULL, &loadConf->globals.bLogStatusMsgs, NULL));
1097+ CHKiRet(regCfSysLineHdlr((uchar *)"errormessagestostderr", 0, eCmdHdlrBinary,
1098+ NULL, &loadConf->globals.bErrMsgToStderr, NULL));
1099+ CHKiRet(regCfSysLineHdlr((uchar *)"abortonuncleanconfig", 0, eCmdHdlrBinary,
1100+ NULL, &loadConf->globals.bAbortOnUncleanConfig, NULL));
1101+ CHKiRet(regCfSysLineHdlr((uchar *)"repeatedmsgreduction", 0, eCmdHdlrBinary,
1102+ NULL, &loadConf->globals.bReduceRepeatMsgs, NULL));
1103+ CHKiRet(regCfSysLineHdlr((uchar *)"debugprinttemplatelist", 0, eCmdHdlrBinary,
1104+ NULL, &(loadConf->globals.bDebugPrintTemplateList), NULL));
1105+ CHKiRet(regCfSysLineHdlr((uchar *)"debugprintmodulelist", 0, eCmdHdlrBinary,
1106+ NULL, &(loadConf->globals.bDebugPrintModuleList), NULL));
1107+ CHKiRet(regCfSysLineHdlr((uchar *)"debugprintcfsyslinehandlerlist", 0, eCmdHdlrBinary,
1108+ NULL, &(loadConf->globals.bDebugPrintCfSysLineHandlerList), NULL));
1109+ CHKiRet(regCfSysLineHdlr((uchar *)"privdroptouser", 0, eCmdHdlrUID,
1110+ NULL, &loadConf->globals.uidDropPriv, NULL));
1111+ CHKiRet(regCfSysLineHdlr((uchar *)"privdroptouserid", 0, eCmdHdlrInt,
1112+ NULL, &loadConf->globals.uidDropPriv, NULL));
1113+ CHKiRet(regCfSysLineHdlr((uchar *)"privdroptogroup", 0, eCmdHdlrGID,
1114+ NULL, &loadConf->globals.gidDropPriv, NULL));
1115+ CHKiRet(regCfSysLineHdlr((uchar *)"privdroptogroupid", 0, eCmdHdlrGID,
1116+ NULL, &loadConf->globals.gidDropPriv, NULL));
1117+ CHKiRet(regCfSysLineHdlr((uchar *)"generateconfiggraph", 0, eCmdHdlrGetWord,
1118+ NULL, &loadConf->globals.pszConfDAGFile, NULL));
1119+ CHKiRet(regCfSysLineHdlr((uchar *)"umask", 0, eCmdHdlrFileCreateMode,
1120+ NULL, &loadConf->globals.umask, NULL));
1121+ CHKiRet(regCfSysLineHdlr((uchar *)"maxopenfiles", 0, eCmdHdlrInt,
1122+ setMaxFiles, NULL, NULL));
1123+
1124+ CHKiRet(regCfSysLineHdlr((uchar *)"actionresumeinterval", 0, eCmdHdlrInt,
1125+ setActionResumeInterval, NULL, NULL));
1126+ CHKiRet(regCfSysLineHdlr((uchar *)"modload", 0, eCmdHdlrCustomHandler,
1127+ conf.doModLoad, NULL, NULL));
1128+ CHKiRet(regCfSysLineHdlr((uchar *)"defaultruleset", 0, eCmdHdlrGetWord,
1129+ setDefaultRuleset, NULL, NULL));
1130+ CHKiRet(regCfSysLineHdlr((uchar *)"ruleset", 0, eCmdHdlrGetWord,
1131+ setCurrRuleset, NULL, NULL));
1132+
1133+ /* handler for "larger" config statements (tie into legacy conf system) */
1134+ CHKiRet(regCfSysLineHdlr((uchar *)"template", 0, eCmdHdlrCustomHandler,
1135+ conf.doNameLine, (void*)DIR_TEMPLATE, NULL));
1136+ CHKiRet(regCfSysLineHdlr((uchar *)"outchannel", 0, eCmdHdlrCustomHandler,
1137+ conf.doNameLine, (void*)DIR_OUTCHANNEL, NULL));
1138+ CHKiRet(regCfSysLineHdlr((uchar *)"allowedsender", 0, eCmdHdlrCustomHandler,
1139+ conf.doNameLine, (void*)DIR_ALLOWEDSENDER, NULL));
1140+
1141+ /* the following are parameters for the main message queue. I have the
1142+ * strong feeling that this needs to go to a different space, but that
1143+ * feeling may be wrong - we'll see how things evolve.
1144+ * rgerhards, 2011-04-21
1145+ */
1146+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuefilename", 0, eCmdHdlrGetWord,
1147+ NULL, &loadConf->globals.mainQ.pszMainMsgQFName, NULL));
1148+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuesize", 0, eCmdHdlrInt,
1149+ NULL, &loadConf->globals.mainQ.iMainMsgQueueSize, NULL));
1150+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuehighwatermark", 0, eCmdHdlrInt,
1151+ NULL, &loadConf->globals.mainQ.iMainMsgQHighWtrMark, NULL));
1152+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuelowwatermark", 0, eCmdHdlrInt,
1153+ NULL, &loadConf->globals.mainQ.iMainMsgQLowWtrMark, NULL));
1154+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuediscardmark", 0, eCmdHdlrInt,
1155+ NULL, &loadConf->globals.mainQ.iMainMsgQDiscardMark, NULL));
1156+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuediscardseverity", 0, eCmdHdlrSeverity,
1157+ NULL, &loadConf->globals.mainQ.iMainMsgQDiscardSeverity, NULL));
1158+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuecheckpointinterval", 0, eCmdHdlrInt,
1159+ NULL, &loadConf->globals.mainQ.iMainMsgQPersistUpdCnt, NULL));
1160+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuesyncqueuefiles", 0, eCmdHdlrBinary,
1161+ NULL, &loadConf->globals.mainQ.bMainMsgQSyncQeueFiles, NULL));
1162+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuetype", 0, eCmdHdlrGetWord,
1163+ setMainMsgQueType, NULL, NULL));
1164+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueueworkerthreads", 0, eCmdHdlrInt,
1165+ NULL, &loadConf->globals.mainQ.iMainMsgQueueNumWorkers, NULL));
1166+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuetimeoutshutdown", 0, eCmdHdlrInt,
1167+ NULL, &loadConf->globals.mainQ.iMainMsgQtoQShutdown, NULL));
1168+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuetimeoutactioncompletion", 0, eCmdHdlrInt,
1169+ NULL, &loadConf->globals.mainQ.iMainMsgQtoActShutdown, NULL));
1170+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuetimeoutenqueue", 0, eCmdHdlrInt,
1171+ NULL, &loadConf->globals.mainQ.iMainMsgQtoEnq, NULL));
1172+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueueworkertimeoutthreadshutdown", 0, eCmdHdlrInt,
1173+ NULL, &loadConf->globals.mainQ.iMainMsgQtoWrkShutdown, NULL));
1174+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuedequeueslowdown", 0, eCmdHdlrInt,
1175+ NULL, &loadConf->globals.mainQ.iMainMsgQDeqSlowdown, NULL));
1176+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueueworkerthreadminimummessages", 0, eCmdHdlrInt,
1177+ NULL, &loadConf->globals.mainQ.iMainMsgQWrkMinMsgs, NULL));
1178+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuemaxfilesize", 0, eCmdHdlrSize,
1179+ NULL, &loadConf->globals.mainQ.iMainMsgQueMaxFileSize, NULL));
1180+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuedequeuebatchsize", 0, eCmdHdlrSize,
1181+ NULL, &loadConf->globals.mainQ.iMainMsgQueDeqBatchSize, NULL));
1182+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuemaxdiskspace", 0, eCmdHdlrSize,
1183+ NULL, &loadConf->globals.mainQ.iMainMsgQueMaxDiskSpace, NULL));
1184+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuesaveonshutdown", 0, eCmdHdlrBinary,
1185+ NULL, &loadConf->globals.mainQ.bMainMsgQSaveOnShutdown, NULL));
1186+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuedequeuetimebegin", 0, eCmdHdlrInt,
1187+ NULL, &loadConf->globals.mainQ.iMainMsgQueueDeqtWinFromHr, NULL));
1188+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuedequeuetimeend", 0, eCmdHdlrInt,
1189+ NULL, &loadConf->globals.mainQ.iMainMsgQueueDeqtWinToHr, NULL));
1190+ /* moddir is a bit hard problem -- because it actually needs to
1191+ * modify a setting that is specific to module.c. The important point
1192+ * is that this action MUST actually be carried out during config load,
1193+ * because we must load modules in order to get their config extensions
1194+ * (no way around).
1195+ * TODO: think about a clean solution
1196+ */
1197+ CHKiRet(regCfSysLineHdlr((uchar *)"moddir", 0, eCmdHdlrGetWord,
1198+ setModDir, NULL, NULL));
1199+
1200+ /* finally, the reset handler */
1201+ CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler,
1202+ resetConfigVariables, NULL, NULL));
1203+
1204+ /* initialize the build-in templates */
1205+ pTmp = template_DebugFormat;
1206+ tplAddLine(ourConf, "RSYSLOG_DebugFormat", &pTmp);
1207+ pTmp = template_SyslogProtocol23Format;
1208+ tplAddLine(ourConf, "RSYSLOG_SyslogProtocol23Format", &pTmp);
1209+ pTmp = template_FileFormat; /* new format for files with high-precision stamp */
1210+ tplAddLine(ourConf, "RSYSLOG_FileFormat", &pTmp);
1211+ pTmp = template_TraditionalFileFormat;
1212+ tplAddLine(ourConf, "RSYSLOG_TraditionalFileFormat", &pTmp);
1213+ pTmp = template_WallFmt;
1214+ tplAddLine(ourConf, " WallFmt", &pTmp);
1215+ pTmp = template_ForwardFormat;
1216+ tplAddLine(ourConf, "RSYSLOG_ForwardFormat", &pTmp);
1217+ pTmp = template_TraditionalForwardFormat;
1218+ tplAddLine(ourConf, "RSYSLOG_TraditionalForwardFormat", &pTmp);
1219+ pTmp = template_StdUsrMsgFmt;
1220+ tplAddLine(ourConf, " StdUsrMsgFmt", &pTmp);
1221+ pTmp = template_StdDBFmt;
1222+ tplAddLine(ourConf, " StdDBFmt", &pTmp);
1223+ pTmp = template_SysklogdFileFormat;
1224+ tplAddLine(ourConf, "RSYSLOG_SysklogdFileFormat", &pTmp);
1225+ pTmp = template_StdPgSQLFmt;
1226+ tplAddLine(ourConf, " StdPgSQLFmt", &pTmp);
1227+ pTmp = template_StdJSONFmt;
1228+ tplAddLine(ourConf, " StdJSONFmt", &pTmp);
1229+ pTmp = template_spoofadr;
1230+ tplLastStaticInit(ourConf, tplAddLine(ourConf, "RSYSLOG_omudpspoofDfltSourceTpl", &pTmp));
1231+
1232+finalize_it:
1233+ RETiRet;
1234+}
1235+
1236+
1237+/* validate the current configuration, generate error messages, do
1238+ * optimizations, etc, etc,...
1239+ */
1240+static inline rsRetVal
1241+validateConf(void)
1242+{
1243+ DEFiRet;
1244+
1245+ /* some checks */
1246+ if(ourConf->globals.mainQ.iMainMsgQueueNumWorkers < 1) {
1247+ errmsg.LogError(0, NO_ERRCODE, "$MainMsgQueueNumWorkers must be at least 1! Set to 1.\n");
1248+ ourConf->globals.mainQ.iMainMsgQueueNumWorkers = 1;
1249+ }
1250+
1251+ if(ourConf->globals.mainQ.MainMsgQueType == QUEUETYPE_DISK) {
1252+ errno = 0; /* for logerror! */
1253+ if(glbl.GetWorkDir() == NULL) {
1254+ errmsg.LogError(0, NO_ERRCODE, "No $WorkDirectory specified - can not run main message queue in 'disk' mode. "
1255+ "Using 'FixedArray' instead.\n");
1256+ ourConf->globals.mainQ.MainMsgQueType = QUEUETYPE_FIXED_ARRAY;
1257+ }
1258+ if(ourConf->globals.mainQ.pszMainMsgQFName == NULL) {
1259+ errmsg.LogError(0, NO_ERRCODE, "No $MainMsgQueueFileName specified - can not run main message queue in "
1260+ "'disk' mode. Using 'FixedArray' instead.\n");
1261+ ourConf->globals.mainQ.MainMsgQueType = QUEUETYPE_FIXED_ARRAY;
1262+ }
1263+ }
1264+ RETiRet;
1265+}
1266+
1267+
1268+/* Load a configuration. This will do all necessary steps to create
1269+ * the in-memory representation of the configuration, including support
1270+ * for multiple configuration languages.
1271+ * Note that to support the legacy language we must provide some global
1272+ * object that holds the currently-being-loaded config ptr.
1273+ * Begun 2011-04-20, rgerhards
1274+ */
1275+rsRetVal
1276+load(rsconf_t **cnf, uchar *confFile)
1277+{
1278+ int iNbrActions;
1279+ int r;
1280+ DEFiRet;
1281+
1282+ CHKiRet(rsconfConstruct(&loadConf));
1283+ourConf = loadConf; // TODO: remove, once ourConf is gone!
1284+
1285+ CHKiRet(loadBuildInModules());
1286+ CHKiRet(initLegacyConf());
1287+
1288+ /* open the configuration file */
1289+ r = cnfSetLexFile((char*)confFile);
1290+ if(r == 0) {
1291+ r = yyparse();
1292+ conf.GetNbrActActions(loadConf, &iNbrActions);
1293+ }
1294+
1295+ if(r == 1) {
1296+ errmsg.LogError(0, RS_RET_CONF_PARSE_ERROR,
1297+ "CONFIG ERROR: could not interpret master "
1298+ "config file '%s'.", confFile);
1299+ ABORT_FINALIZE(RS_RET_CONF_PARSE_ERROR);
1300+ } else if(iNbrActions == 0) {
1301+ errmsg.LogError(0, RS_RET_NO_ACTIONS, "CONFIG ERROR: there are no "
1302+ "active actions configured. Inputs will "
1303+ "run, but no output whatsoever is created.");
1304+ ABORT_FINALIZE(RS_RET_NO_ACTIONS);
1305+ }
1306+ tellLexEndParsing();
1307+ rulesetOptimizeAll(loadConf);
1308+
1309+ tellCoreConfigLoadDone();
1310+ tellModulesConfigLoadDone();
1311+
1312+ tellModulesCheckConfig();
1313+ CHKiRet(validateConf());
1314+
1315+ /* we are done checking the config - now validate if we should actually run or not.
1316+ * If not, terminate. -- rgerhards, 2008-07-25
1317+ * TODO: iConfigVerify -- should it be pulled from the config, or leave as is (option)?
1318+ */
1319+ if(iConfigVerify) {
1320+ if(iRet == RS_RET_OK)
1321+ iRet = RS_RET_VALIDATION_RUN;
1322+ FINALIZE;
1323+ }
1324+
1325+ /* all OK, pass loaded conf to caller */
1326+ *cnf = loadConf;
1327+// TODO: enable this once all config code is moved to here! loadConf = NULL;
1328+
1329+ dbgprintf("rsyslog finished loading master config %p\n", loadConf);
1330+ rsconfDebugPrint(loadConf);
1331+
1332+finalize_it:
1333+ RETiRet;
1334+}
1335+
1336+
1337+/* queryInterface function
1338+ */
1339+BEGINobjQueryInterface(rsconf)
1340+CODESTARTobjQueryInterface(rsconf)
1341+ if(pIf->ifVersion != rsconfCURR_IF_VERSION) { /* check for current version, increment on each change */
1342+ ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED);
1343+ }
1344+
1345+ /* ok, we have the right interface, so let's fill it
1346+ * Please note that we may also do some backwards-compatibility
1347+ * work here (if we can support an older interface version - that,
1348+ * of course, also affects the "if" above).
1349+ */
1350+ pIf->Construct = rsconfConstruct;
1351+ pIf->ConstructFinalize = rsconfConstructFinalize;
1352+ pIf->Destruct = rsconfDestruct;
1353+ pIf->DebugPrint = rsconfDebugPrint;
1354+ pIf->Load = load;
1355+ pIf->Activate = activate;
1356+finalize_it:
1357+ENDobjQueryInterface(rsconf)
1358+
1359+
1360+/* Initialize the rsconf class. Must be called as the very first method
1361+ * before anything else is called inside this class.
1362+ */
1363+BEGINObjClassInit(rsconf, 1, OBJ_IS_CORE_MODULE) /* class, version */
1364+ /* request objects we use */
1365+ CHKiRet(objUse(ruleset, CORE_COMPONENT));
1366+ CHKiRet(objUse(module, CORE_COMPONENT));
1367+ CHKiRet(objUse(conf, CORE_COMPONENT));
1368+ CHKiRet(objUse(errmsg, CORE_COMPONENT));
1369+ CHKiRet(objUse(glbl, CORE_COMPONENT));
1370+ CHKiRet(objUse(datetime, CORE_COMPONENT));
1371+ CHKiRet(objUse(parser, CORE_COMPONENT));
1372+
1373+ /* now set our own handlers */
1374+ OBJSetMethodHandler(objMethod_DEBUGPRINT, rsconfDebugPrint);
1375+ OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, rsconfConstructFinalize);
1376+ENDObjClassInit(rsconf)
1377+
1378+
1379+/* De-initialize the rsconf class.
1380+ */
1381+BEGINObjClassExit(rsconf, OBJ_IS_CORE_MODULE) /* class, version */
1382+ objRelease(ruleset, CORE_COMPONENT);
1383+ objRelease(module, CORE_COMPONENT);
1384+ objRelease(conf, CORE_COMPONENT);
1385+ objRelease(errmsg, CORE_COMPONENT);
1386+ objRelease(glbl, CORE_COMPONENT);
1387+ objRelease(datetime, CORE_COMPONENT);
1388+ objRelease(parser, CORE_COMPONENT);
1389+ENDObjClassExit(rsconf)
1390+
1391+/* vi:set ai:
1392+ */
1393
1394=== modified file '.pc/applied-patches'
1395--- .pc/applied-patches 2013-10-21 15:31:38 +0000
1396+++ .pc/applied-patches 2013-12-04 13:07:52 +0000
1397@@ -1,1 +1,2 @@
1398 01-dont_create_db.patch
1399+10-initgroups.patch
1400
1401=== modified file 'debian/changelog'
1402--- debian/changelog 2013-10-21 15:31:38 +0000
1403+++ debian/changelog 2013-12-04 13:07:52 +0000
1404@@ -1,3 +1,15 @@
1405+rsyslog (7.4.4-1ubuntu2) UNRELEASED; urgency=low
1406+
1407+ * debian/rsyslog.postinst: Make sure /var/log is owned by group syslog and
1408+ is group-writeable (LP: #1256695).
1409+ * Ensure that rsyslogd can create files in group adm, even when dropping
1410+ group privileges to syslog (LP: #484336):
1411+ - debian/patches/10-initgroups.patch: Try to set appropriate
1412+ supplementary groups before dropping UID.
1413+ - debian/rsyslog.postinst: Add syslog user to group adm.
1414+
1415+ -- Colin Watson <cjwatson@ubuntu.com> Wed, 04 Dec 2013 11:46:11 +0000
1416+
1417 rsyslog (7.4.4-1ubuntu1) trusty; urgency=low
1418
1419 * Merge from Debian unstable, remaining changes:
1420
1421=== added file 'debian/patches/10-initgroups.patch'
1422--- debian/patches/10-initgroups.patch 1970-01-01 00:00:00 +0000
1423+++ debian/patches/10-initgroups.patch 2013-12-04 13:07:52 +0000
1424@@ -0,0 +1,44 @@
1425+Description: Try to set supplementary groups before dropping UID
1426+Author: Colin Watson <cjwatson@ubuntu.com>
1427+Bug-Ubuntu: https://bugs.launchpad.net/bugs/484336
1428+Bug-Ubuntu: https://bugs.launchpad.net/bugs/1256695
1429+Bug-Ubuntu: https://bugs.launchpad.net/bugs/1257633
1430+Forwarded: no
1431+Last-Update: 2013-12-04
1432+
1433+Index: b/runtime/rsconf.c
1434+===================================================================
1435+--- a/runtime/rsconf.c
1436++++ b/runtime/rsconf.c
1437+@@ -27,6 +27,7 @@
1438+ #include <string.h>
1439+ #include <errno.h>
1440+ #include <unistd.h>
1441++#include <pwd.h>
1442+ #include <grp.h>
1443+ #include <stdarg.h>
1444+ #include <sys/resource.h>
1445+@@ -533,6 +534,23 @@
1446+ {
1447+ int res;
1448+ uchar szBuf[1024];
1449++ struct passwd *pw;
1450++ gid_t gid;
1451++
1452++ /* Try to set appropriate supplementary groups for this user.
1453++ * Failure is not fatal.
1454++ */
1455++ pw = getpwuid(iUid);
1456++ if (pw) {
1457++ gid = getgid();
1458++ res = initgroups(pw->pw_name, gid);
1459++ DBGPRINTF("initgroups(%s, %d): %d\n", pw->pw_name, gid, res);
1460++ } else {
1461++ rs_strerror_r(errno, szBuf, sizeof(szBuf));
1462++ errmsg.LogError(0, NO_ERRCODE,
1463++ "could not get username for userid %d: %s",
1464++ iUid, szBuf);
1465++ }
1466+
1467+ res = setuid(iUid);
1468+ if(res) {
1469
1470=== modified file 'debian/patches/series'
1471--- debian/patches/series 2013-10-21 15:31:38 +0000
1472+++ debian/patches/series 2013-12-04 13:07:52 +0000
1473@@ -1,2 +1,3 @@
1474 # Debian patches for rsyslog
1475 01-dont_create_db.patch
1476+10-initgroups.patch
1477
1478=== modified file 'debian/rsyslog.postinst'
1479--- debian/rsyslog.postinst 2013-10-21 15:31:38 +0000
1480+++ debian/rsyslog.postinst 2013-12-04 13:07:52 +0000
1481@@ -24,10 +24,16 @@
1482 ucfr rsyslog $user_conf
1483
1484 adduser --system --group --no-create-home --quiet syslog || true
1485+ adduser syslog adm || true
1486
1487 # fix ownership of work directory (LP: #1075901)
1488 chown syslog:adm /var/spool/rsyslog
1489
1490+ # ensure that rsyslogd can create log files after dropping
1491+ # privileges
1492+ chgrp syslog /var/log
1493+ chmod g+w /var/log
1494+
1495 # /run transition (Bug: #633036)
1496 if dpkg --compare-versions "$2" lt "5.8.2-2"; then
1497 rm -f /lib/init/rw/sendsigs.omit.d/rsyslog
1498
1499=== modified file 'runtime/rsconf.c'
1500--- runtime/rsconf.c 2013-03-18 16:21:35 +0000
1501+++ runtime/rsconf.c 2013-12-04 13:07:52 +0000
1502@@ -27,6 +27,7 @@
1503 #include <string.h>
1504 #include <errno.h>
1505 #include <unistd.h>
1506+#include <pwd.h>
1507 #include <grp.h>
1508 #include <stdarg.h>
1509 #include <sys/resource.h>
1510@@ -533,6 +534,23 @@
1511 {
1512 int res;
1513 uchar szBuf[1024];
1514+ struct passwd *pw;
1515+ gid_t gid;
1516+
1517+ /* Try to set appropriate supplementary groups for this user.
1518+ * Failure is not fatal.
1519+ */
1520+ pw = getpwuid(iUid);
1521+ if (pw) {
1522+ gid = getgid();
1523+ res = initgroups(pw->pw_name, gid);
1524+ DBGPRINTF("initgroups(%s, %d): %d\n", pw->pw_name, gid, res);
1525+ } else {
1526+ rs_strerror_r(errno, szBuf, sizeof(szBuf));
1527+ errmsg.LogError(0, NO_ERRCODE,
1528+ "could not get username for userid %d: %s",
1529+ iUid, szBuf);
1530+ }
1531
1532 res = setuid(iUid);
1533 if(res) {

Subscribers

People subscribed via source and target branches

to all changes: