diff options
Diffstat (limited to 'runtime/rsconf.c')
-rw-r--r-- | runtime/rsconf.c | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/runtime/rsconf.c b/runtime/rsconf.c index 47a6f00b..2a87756f 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -29,6 +29,8 @@ #include <assert.h> #include <string.h> #include <errno.h> +#include <unistd.h> +#include <grp.h> #include <sys/resource.h> #include <sys/types.h> #include <sys/stat.h> @@ -60,6 +62,8 @@ #include "smtradfwd.h" #include "parser.h" #include "outchannel.h" +#include "threads.h" +#include "dirty.h" /* static data */ DEFobjStaticHelpers @@ -198,6 +202,139 @@ CODESTARTobjDebugPrint(rsconf) ENDobjDebugPrint(rsconf) +/* drop to specified group + * if something goes wrong, the function never returns + * Note that such an abort can cause damage to on-disk structures, so we should + * re-design the "interface" in the long term. -- rgerhards, 2008-11-26 + */ +static void doDropPrivGid(int iGid) +{ + int res; + uchar szBuf[1024]; + + res = setgroups(0, NULL); /* remove all supplementary group IDs */ + if(res) { + perror("could not remove supplemental group IDs"); + exit(1); + } + DBGPRINTF("setgroups(0, NULL): %d\n", res); + res = setgid(iGid); + if(res) { + /* if we can not set the userid, this is fatal, so let's unconditionally abort */ + perror("could not set requested group id"); + exit(1); + } + DBGPRINTF("setgid(%d): %d\n", iGid, res); + snprintf((char*)szBuf, sizeof(szBuf)/sizeof(uchar), "rsyslogd's groupid changed to %d", iGid); + logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, szBuf, 0); +} + + +/* drop to specified user + * if something goes wrong, the function never returns + * Note that such an abort can cause damage to on-disk structures, so we should + * re-design the "interface" in the long term. -- rgerhards, 2008-11-19 + */ +static void doDropPrivUid(int iUid) +{ + int res; + uchar szBuf[1024]; + + res = setuid(iUid); + if(res) { + /* if we can not set the userid, this is fatal, so let's unconditionally abort */ + perror("could not set requested userid"); + exit(1); + } + DBGPRINTF("setuid(%d): %d\n", iUid, res); + snprintf((char*)szBuf, sizeof(szBuf)/sizeof(uchar), "rsyslogd's userid changed to %d", iUid); + logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, szBuf, 0); +} + + + +/* drop privileges. This will drop to the configured privileges, if + * set by the user. After this method has been executed, the previous + * privileges can no be re-gained. + */ +static inline rsRetVal +dropPrivileges(rsconf_t *cnf) +{ + DEFiRet; + + /* If instructed to do so, we now drop privileges. Note that this is not 100% secure, + * because outputs are already running at this time. However, we can implement + * dropping of privileges rather quickly and it will work in many cases. While it is not + * the ultimate solution, the current one is still much better than not being able to + * drop privileges at all. Doing it correctly, requires a change in architecture, which + * we should do over time. TODO -- rgerhards, 2008-11-19 + */ + if(cnf->globals.gidDropPriv != 0) { + doDropPrivGid(ourConf->globals.gidDropPriv); + } + + if(cnf->globals.uidDropPriv != 0) { + doDropPrivUid(ourConf->globals.uidDropPriv); + } + + RETiRet; +} + + +/* Actually run the input modules. This happens after privileges are dropped, + * if that is requested. + */ +static rsRetVal +runInputModules(void) +{ + modInfo_t *pMod; + int bNeedsCancel; + + BEGINfunc + /* loop through all modules and activate them (brr...) */ + pMod = module.GetNxtType(NULL, eMOD_IN); + while(pMod != NULL) { + if(pMod->mod.im.bCanRun) { + /* activate here */ + bNeedsCancel = (pMod->isCompatibleWithFeature(sFEATURENonCancelInputTermination) == RS_RET_OK) ? + 0 : 1; + thrdCreate(pMod->mod.im.runInput, pMod->mod.im.afterRun, bNeedsCancel); + } + pMod = module.GetNxtType(pMod, eMOD_IN); + } + + ENDfunc + return RS_RET_OK; /* intentional: we do not care about module errors */ +} + + +/* Start the input modules. This function will probably undergo big changes + * while we implement the input module interface. For now, it does the most + * important thing to get at least my poor initial input modules up and + * running. Almost no config option is taken. + * rgerhards, 2007-12-14 + */ +static rsRetVal +startInputModules(void) +{ + DEFiRet; + modInfo_t *pMod; + + /* loop through all modules and activate them (brr...) */ + pMod = module.GetNxtType(NULL, eMOD_IN); + while(pMod != NULL) { + iRet = pMod->mod.im.willRun(); + pMod->mod.im.bCanRun = (iRet == RS_RET_OK); + if(!pMod->mod.im.bCanRun) { + DBGPRINTF("module %lx will not run, iRet %d\n", (unsigned long) pMod, iRet); + } + pMod = module.GetNxtType(pMod, eMOD_IN); + } + + ENDfunc + return RS_RET_OK; /* intentional: we do not care about module errors */ +} + /* Activate an already-loaded configuration. The configuration will become * the new running conf (if successful). Note that in theory this method may * be called when there already is a running conf. In practice, the current @@ -208,8 +345,33 @@ rsRetVal activate(rsconf_t *cnf) { DEFiRet; + +# if 0 /* currently the DAG is not supported -- code missing! */ + /* TODO: re-enable this functionality some time later! */ + /* check if we need to generate a config DAG and, if so, do that */ + if(ourConf->globals.pszConfDAGFile != NULL) + generateConfigDAG(ourConf->globals.pszConfDAGFile); +# endif + + /* 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 + * shuffled to down here once we have everything in input modules. + * rgerhards, 2007-12-14 + * NOTE: as of 2009-06-29, the input modules are initialized, but not yet run. + * Keep in mind. though, that the outputs already run if the queue was + * persisted to disk. -- rgerhards + */ + startInputModules(); + + CHKiRet(dropPrivileges(cnf)); + + /* finally let the inputs run... */ + runInputModules(); + runConf = cnf; dbgprintf("configuration %p activated\n", cnf); + +finalize_it: RETiRet; } @@ -732,6 +894,14 @@ ourConf = loadConf; // TODO: remove, once ourConf is gone! CHKiRet(validateConf()); + /* we are done checking the config - now validate if we should actually run or not. + * If not, terminate. -- rgerhards, 2008-07-25 + * TODO: iConfigVerify -- should it be pulled from the config, or leave as is (option)? + */ + if(iConfigVerify) { + ABORT_FINALIZE(RS_RET_VALIDATION_RUN); + } + /* all OK, pass loaded conf to caller */ *cnf = loadConf; // TODO: enable this once all config code is moved to here! loadConf = NULL; @@ -739,6 +909,9 @@ ourConf = loadConf; // TODO: remove, once ourConf is gone! dbgprintf("rsyslog finished loading initial config %p\n", loadConf); rsconfDebugPrint(loadConf); + /* return warning state if we had some acceptable problems */ + if(bHadConfigErr) + iRet = RS_RET_NONFATAL_CONFIG_ERR; finalize_it: RETiRet; } |