summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRainer Gerhards <rgerhards@adiscon.com>2011-05-06 10:06:32 +0200
committerRainer Gerhards <rgerhards@adiscon.com>2011-05-06 10:06:32 +0200
commitff2bb192f2c566f189a9d104d83d7a70c7888774 (patch)
tree7737c436f7f3ed611535879654d59e672cfd69c3
parentb056c258d7bab528034ec8c8749cdcf0d0102268 (diff)
downloadrsyslog-ff2bb192f2c566f189a9d104d83d7a70c7888774.tar.gz
rsyslog-ff2bb192f2c566f189a9d104d83d7a70c7888774.tar.xz
rsyslog-ff2bb192f2c566f189a9d104d83d7a70c7888774.zip
step: conf interface now natively supports priv drop
-rw-r--r--doc/design.tex74
-rw-r--r--plugins/imtcp/imtcp.c12
-rw-r--r--plugins/imudp/imudp.c10
-rw-r--r--runtime/module-template.h37
-rw-r--r--runtime/modules.c11
-rw-r--r--runtime/modules.h1
-rw-r--r--runtime/rsconf.c50
7 files changed, 174 insertions, 21 deletions
diff --git a/doc/design.tex b/doc/design.tex
index a3ec8f45..1def3fb7 100644
--- a/doc/design.tex
+++ b/doc/design.tex
@@ -811,10 +811,80 @@ b) we push the failed message back to the main queue, but with an indication
that it failed in an action. This is harder to implement and most importantly
harder to understand/configure, but more flexible
+\section{Configuration System}
+The configration system found in all versions up to v5 is based on sysklogd's
+legacy. It does not have any clear distinction between config load and
+activation. Starting with v6, a new config system is build. That new system
+offers the necessary distinction. In the long term, the configuration language
+will be enhanced towards the more flexible and easy to use RainerScript idea.
+
+\section{Plugin Interface}
+This section describes some aspects of the plugin interface.
+\subsection{Configuration Related}
+To support the new v2 config system, plugins need to publish a number of entry
+points that will be called by the rsyslog configuration section at various
+stages of the configration load, activation and deactivation process. This list
+may be extended as the configuration interface evolves.
+
+Plugins must not necessarily implement support for the v2 config system. If
+they do, the ``beginCnfLoad'' entry point serves as a flag telling that support
+is available. In that case, all other entry points need to be defined as well.
+If a module does not support the v2 config system, it can still be run, but be
+configured only via the legacy config system. Note that with the old system
+there are also problems with droping privileges. So a legacy module may not
+work correctly if privileges are dropped.
+
+The following entry points are available:
+\begin{enumerate}
+ \item \emph{beginCnfLoad} -- called when a new config load begins. Only one
+config load can be active at one time (no concurrent loads).
+ \item \emph{endCnfLoad} -- called when config load ends. This gives the module
+a chance to do final changes and some cleanup.
+ \item \emph{checkCnf} -- called by the framework to verify a configuration.
+ \item \emph{activateCnfPrePrivDrop} -- called by the framework to activate a
+configuration before privileges are dropped. This is an optional entry point
+that shall only be implemented by plugins that need the do some processing
+before rsyslog drops privileges. Processing inside this entry point should be
+limited to what is absolutely necessary. The main activation work should be
+done in activateCnf() as usual.
+ \item \emph{activateCnf} -- called by the framework to activate a
+configuration.
+\item \emph{freeCnf} -- called by the framework to free
+(deallocate) a configuration.
+\end{enumerate}
+
+In the current implementation, entry points are sequentially called as given
+above. However, this will change. It is guaranteed that
+\begin{itemize}
+ \item beginCnfLoad() will be followed by a matching endCnfLoad() and there
+will be no new call to beginCnfLoad() before endCnfLoad() has been called. This
+means no nested config load needs to be supported,
+ \item checkCnf() may be called at any time, even during a config load phase.
+However, the config to check is a fully loaded one.
+ \item activateCnfPrePrivDrop(), if provided, will always be called before
+activateCnf() is called. No other config-related calls will be made in between.
+\end{itemize}
+
+\subsubsection{Output Modules}
+The v1 config load system for output modules seems to provide all functionality
+necessary to support the v2 system as well. As such, we currently do not
+require output modules to implement the new calls to be fully supported by the
+v2 system.
+
\section{Network Stream Subsystem}
-The idea of network streams was introduced when we implemented RFC5425 (syslog over TLS) in 2008. The core idea is to encapsulate all stream-oriented network data transfer into a single transport layer and make the upper layers independent of actual transport being used. This is in line with the traditional layer approaches in communication systems.
+The idea of network streams was introduced when we implemented RFC5425 (syslog
+over TLS) in 2008. The core idea is to encapsulate all stream-oriented network
+data transfer into a single transport layer and make the upper layers
+independent of actual transport being used. This is in line with the traditional
+layer approaches in communication systems.
+
+Under this system, the upper layer provides plugins to send and receive streams
+of syslog data. Framing is provided by the upper layer. The upper layer itself
+is integrated in input and output plugins, which then are used to provide
+application-level syslog message objects to and from the rsyslog core. To these
+upper layers, the netstream layer provides reliable and sequenced message
+delivery with much of the same semantics as a usual TCP stream.
-Under this system, the upper layer provides plugins to send and receive streams of syslog data. Framing is provided by the upper layer. The upper layer itself is integrated in input and output plugins, which then are used to provide application-level syslog message objects to and from the rsyslog core. To these upper layers, the netstream layer provides reliable and sequenced message delivery with much of the same semantics as a usual TCP stream.
\begin{figure}
\begin{center}
diff --git a/plugins/imtcp/imtcp.c b/plugins/imtcp/imtcp.c
index 75987aed..3978ff5d 100644
--- a/plugins/imtcp/imtcp.c
+++ b/plugins/imtcp/imtcp.c
@@ -266,6 +266,7 @@ addListner(modConfData_t *modConf, instanceConf_t *inst)
}
/* initialized, now add socket and listener params */
+ DBGPRINTF("imtcp: trying to add port *:%s\n", inst->pszBindPort);
CHKiRet(tcpsrv.SetRuleset(pOurTcpsrv, inst->pBindRuleset));
CHKiRet(tcpsrv.SetInputName(pOurTcpsrv, inst->pszInputName == NULL ?
UCHAR_CONSTANT("imtcp") : inst->pszInputName));
@@ -329,9 +330,9 @@ CODESTARTcheckCnf
ENDcheckCnf
-BEGINactivateCnf
+BEGINactivateCnfPrePrivDrop
instanceConf_t *inst;
-CODESTARTactivateCnf
+CODESTARTactivateCnfPrePrivDrop
runModConf = pModConf;
for(inst = runModConf->root ; inst != NULL ; inst = inst->next) {
addListner(pModConf, inst);
@@ -339,6 +340,12 @@ CODESTARTactivateCnf
if(pOurTcpsrv == NULL)
ABORT_FINALIZE(RS_RET_NO_RUN);
finalize_it:
+ENDactivateCnfPrePrivDrop
+
+
+BEGINactivateCnf
+CODESTARTactivateCnf
+ /* sorry, nothing to do here... */
ENDactivateCnf
@@ -422,6 +429,7 @@ BEGINqueryEtryPt
CODESTARTqueryEtryPt
CODEqueryEtryPt_STD_IMOD_QUERIES
CODEqueryEtryPt_STD_CONF2_QUERIES
+CODEqueryEtryPt_STD_CONF2_PREPRIVDROP_QUERIES
CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES
ENDqueryEtryPt
diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c
index ee5c39e5..0df80e87 100644
--- a/plugins/imudp/imudp.c
+++ b/plugins/imudp/imudp.c
@@ -657,9 +657,9 @@ CODESTARTcheckCnf
ENDcheckCnf
-BEGINactivateCnf
+BEGINactivateCnfPrePrivDrop
instanceConf_t *inst;
-CODESTARTactivateCnf
+CODESTARTactivateCnfPrePrivDrop
runModConf = pModConf;
for(inst = runModConf->root ; inst != NULL ; inst = inst->next) {
addListner(inst);
@@ -672,7 +672,12 @@ CODESTARTactivateCnf
}
setSchedParams(pModConf);
+finalize_it:
+ENDactivateCnfPrePrivDrop
+
+BEGINactivateCnf
+CODESTARTactivateCnf
/* caching various settings */
iMaxLine = glbl.GetMaxLine();
CHKmalloc(pRcvBuf = MALLOC((iMaxLine + 1) * sizeof(char)));
@@ -745,6 +750,7 @@ BEGINqueryEtryPt
CODESTARTqueryEtryPt
CODEqueryEtryPt_STD_IMOD_QUERIES
CODEqueryEtryPt_STD_CONF2_QUERIES
+CODEqueryEtryPt_STD_CONF2_PREPRIVDROP_QUERIES
CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES
ENDqueryEtryPt
diff --git a/runtime/module-template.h b/runtime/module-template.h
index f44cb54a..0440d02d 100644
--- a/runtime/module-template.h
+++ b/runtime/module-template.h
@@ -478,6 +478,15 @@ static rsRetVal queryEtryPt(uchar *name, rsRetVal (**pEtryPoint)())\
*pEtryPoint = freeCnf;\
}
+
+/* the following block is to be added for modules that require
+ * pre priv drop activation support.
+ */
+#define CODEqueryEtryPt_STD_CONF2_PREPRIVDROP_QUERIES \
+ else if(!strcmp((char*) name, "activateCnfPrePrivDrop")) {\
+ *pEtryPoint = activateCnfPrePrivDrop;\
+ }
+
/* the following definition is the standard block for queryEtryPt for LIBRARY
* modules. This can be used if no specific handling (e.g. to cover version
* differences) is needed.
@@ -622,7 +631,7 @@ static rsRetVal modExit(void)\
* the module. -- rgerards, 2011-05-03
*/
#define BEGINbeginCnfLoad \
-static rsRetVal beginCnfLoad(modConfData_t **ptr, rsconf_t *pConf)\
+static rsRetVal beginCnfLoad(modConfData_t **ptr, __attribute__((unused)) rsconf_t *pConf)\
{\
modConfData_t *pModConf; \
DEFiRet;
@@ -650,7 +659,7 @@ static rsRetVal beginCnfLoad(modConfData_t **ptr, rsconf_t *pConf)\
#define BEGINendCnfLoad \
static rsRetVal endCnfLoad(modConfData_t *ptr)\
{\
- modConfData_t *pModConf = (modConfData_t*) ptr; \
+ modConfData_t __attribute__((unused)) *pModConf = (modConfData_t*) ptr; \
DEFiRet;
#define CODESTARTendCnfLoad
@@ -672,7 +681,7 @@ static rsRetVal endCnfLoad(modConfData_t *ptr)\
#define BEGINcheckCnf \
static rsRetVal checkCnf(modConfData_t *ptr)\
{\
- modConfData_t *pModConf = (modConfData_t*) ptr; \
+ modConfData_t __attribute__((unused)) *pModConf = (modConfData_t*) ptr; \
DEFiRet;
#define CODESTARTcheckCnf
@@ -682,6 +691,26 @@ static rsRetVal checkCnf(modConfData_t *ptr)\
}
+/* activateCnfPrePrivDrop()
+ * Initial config activation, before dropping privileges. This is an optional
+ * entry points that should only be implemented by those module that really need
+ * it. Processing should be limited to the minimum possible. Main activation
+ * should happen in the normal activateCnf() call.
+ * rgerhards, 2011-05-06
+ */
+#define BEGINactivateCnfPrePrivDrop \
+static rsRetVal activateCnfPrePrivDrop(modConfData_t *ptr)\
+{\
+ modConfData_t *pModConf = (modConfData_t*) ptr; \
+ DEFiRet;
+
+#define CODESTARTactivateCnfPrePrivDrop
+
+#define ENDactivateCnfPrePrivDrop \
+ RETiRet;\
+}
+
+
/* activateCnf()
* This activates the provided config, and may report errors if they are detected
* during activation.
@@ -690,7 +719,7 @@ static rsRetVal checkCnf(modConfData_t *ptr)\
#define BEGINactivateCnf \
static rsRetVal activateCnf(modConfData_t *ptr)\
{\
- modConfData_t *pModConf = (modConfData_t*) ptr; \
+ modConfData_t __attribute__((unused)) *pModConf = (modConfData_t*) ptr; \
DEFiRet;
#define CODESTARTactivateCnf
diff --git a/runtime/modules.c b/runtime/modules.c
index bf944dba..4cd1ef4f 100644
--- a/runtime/modules.c
+++ b/runtime/modules.c
@@ -371,7 +371,6 @@ addModToCnfList(modInfo_t *pThis)
pNew->next = NULL;
pNew->pMod = pThis;
-dbgprintf("XXXX: beginCnfLoad %p\n", pThis->beginCnfLoad);
if(pThis->beginCnfLoad != NULL) {
CHKiRet(pThis->beginCnfLoad(&pNew->modCnf, loadConf));
}
@@ -528,6 +527,12 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_
CHKiRet((*pNew->modQueryEtryPt)((uchar*)"freeCnf", &pNew->freeCnf));
CHKiRet((*pNew->modQueryEtryPt)((uchar*)"checkCnf", &pNew->checkCnf));
CHKiRet((*pNew->modQueryEtryPt)((uchar*)"activateCnf", &pNew->activateCnf));
+ localRet = (*pNew->modQueryEtryPt)((uchar*)"activateCnfPrePrivDrop", &pNew->activateCnfPrePrivDrop);
+ if(localRet == RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) {
+ pNew->activateCnfPrePrivDrop = NULL;
+ } else {
+ CHKiRet(localRet);
+ }
} else if(localRet == RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) {
pNew->beginCnfLoad = NULL; /* flag as non-present */
} else {
@@ -706,7 +711,9 @@ static void modPrintList(void)
dbgprintf("\tdbgPrintInstInfo: 0x%lx\n", (unsigned long) pMod->dbgPrintInstInfo);
dbgprintf("\tfreeInstance: 0x%lx\n", (unsigned long) pMod->freeInstance);
dbgprintf("\tbeginCnfLoad: 0x%lx\n", (unsigned long) pMod->beginCnfLoad);
- dbgprintf("\tendCnfLoad: 0x%lx\n", (unsigned long) pMod->endCnfLoad);
+ dbgprintf("\tcheckCnf: 0x%lx\n", (unsigned long) pMod->checkCnf);
+ dbgprintf("\tactivateCnfPrePrivDrop: 0x%lx\n", (unsigned long) pMod->activateCnfPrePrivDrop);
+ dbgprintf("\tactivateCnf: 0x%lx\n", (unsigned long) pMod->activateCnf);
dbgprintf("\tfreeCnf: 0x%lx\n", (unsigned long) pMod->freeCnf);
switch(pMod->eType) {
case eMOD_OUT:
diff --git a/runtime/modules.h b/runtime/modules.h
index e3af1ad9..a62b1750 100644
--- a/runtime/modules.h
+++ b/runtime/modules.h
@@ -115,6 +115,7 @@ struct modInfo_s {
rsRetVal (*beginCnfLoad)(void*newCnf, rsconf_t *pConf);
rsRetVal (*endCnfLoad)(void*Cnf);
rsRetVal (*checkCnf)(void*Cnf);
+ rsRetVal (*activateCnfPrePrivDrop)(void*Cnf);
rsRetVal (*activateCnf)(void*Cnf); /* make provided config the running conf */
rsRetVal (*freeCnf)(void*Cnf);
/* end v2 config system specific */
diff --git a/runtime/rsconf.c b/runtime/rsconf.c
index 92c17b5c..94190d76 100644
--- a/runtime/rsconf.c
+++ b/runtime/rsconf.c
@@ -296,7 +296,7 @@ dropPrivileges(rsconf_t *cnf)
/* Tell input modules that the config parsing stage is over. */
static rsRetVal
-tellInputsConfigLoadDone(void)
+tellModulesConfigLoadDone(void)
{
cfgmodules_etry_t *node;
@@ -316,7 +316,7 @@ tellInputsConfigLoadDone(void)
/* Tell input modules to verify config object */
static rsRetVal
-tellInputsCheckConfig(void)
+tellModulesCheckConfig(void)
{
cfgmodules_etry_t *node;
rsRetVal localRet;
@@ -343,9 +343,40 @@ tellInputsCheckConfig(void)
}
-/* Tell input modules to activate current running config */
+/* Tell modules to activate current running config (pre privilege drop) */
static rsRetVal
-tellInputsActivateConfig(void)
+tellModulesActivateConfigPrePrivDrop(void)
+{
+ cfgmodules_etry_t *node;
+ rsRetVal localRet;
+
+ BEGINfunc
+ DBGPRINTF("telling modules to activate config (before dropping privs) %p\n", runConf);
+ node = module.GetNxtCnfType(runConf, NULL, eMOD_ANY);
+ while(node != NULL) {
+ if( node->pMod->beginCnfLoad != NULL
+ && node->pMod->activateCnfPrePrivDrop != NULL
+ && node->canActivate) {
+ DBGPRINTF("activating config %p for module %s\n",
+ runConf, node->pMod->pszName);
+ localRet = node->pMod->activateCnfPrePrivDrop(node->modCnf);
+ if(localRet != RS_RET_OK) {
+ errmsg.LogError(0, localRet, "activation of module %s failed",
+ node->pMod->pszName);
+ node->canActivate = 0; /* in a sense, could not activate... */
+ }
+ }
+ node = module.GetNxtCnfType(runConf, node, eMOD_IN);
+ }
+
+ ENDfunc
+ return RS_RET_OK; /* intentional: we do not care about module errors */
+}
+
+
+/* Tell modules to activate current running config */
+static rsRetVal
+tellModulesActivateConfig(void)
{
cfgmodules_etry_t *node;
rsRetVal localRet;
@@ -398,7 +429,7 @@ runInputModules(void)
}
-/* Make the input modules check if they are ready to start.
+/* Make the modules check if they are ready to start.
*/
static rsRetVal
startInputModules(void)
@@ -463,8 +494,8 @@ activate(rsconf_t *cnf)
if(ourConf->globals.pszConfDAGFile != NULL)
generateConfigDAG(ourConf->globals.pszConfDAGFile);
# endif
- tellInputsConfigLoadDone();
- tellInputsCheckConfig();
+ tellModulesConfigLoadDone();
+ tellModulesCheckConfig();
/* the output part and the queue is now ready to run. So it is a good time
* to initialize the inputs. Please note that the net code above should be
@@ -474,11 +505,12 @@ activate(rsconf_t *cnf)
* Keep in mind. though, that the outputs already run if the queue was
* persisted to disk. -- rgerhards
*/
- tellInputsActivateConfig();
- startInputModules();
+ tellModulesActivateConfigPrePrivDrop();
CHKiRet(dropPrivileges(cnf));
+ tellModulesActivateConfig();
+ startInputModules();
CHKiRet(activateActions());
CHKiRet(activateMainQueue());
/* finally let the inputs run... */