From 57c9a3accee3a3e9b46d984c76c9aae7e2ec9c27 Mon Sep 17 00:00:00 2001
From: Rainer Gerhards
Date: Wed, 19 Nov 2008 13:20:31 +0100
Subject: exprimental implementaiton of $PrivDropToUser directive
... which permits to drop root privileges. This is not a completely
secure way of dropping permissions, e.g. the group permissions need
to be dropped, too. Also, there are several vulnerability Windows (see
code comments). Finally, at least the imklog module on linux does
not work when privileges are dropped. This code may still be a
valuable addition, and so I have created an experimental branch so
that people can check it out.
---
tools/syslogd.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 46 insertions(+), 4 deletions(-)
diff --git a/tools/syslogd.c b/tools/syslogd.c
index 7145779d..51ce1830 100644
--- a/tools/syslogd.c
+++ b/tools/syslogd.c
@@ -272,6 +272,7 @@ static int bHaveMainQueue = 0;/* set to 1 if the main queue - in queueing mode -
* If the main queue is either not yet ready or not running in
* queueing mode (mode DIRECT!), then this is set to 0.
*/
+static int uidDropPriv = 0; /* user-id to which priveleges should be dropped to (AFTER init()!) */
extern int errno;
@@ -2063,6 +2064,30 @@ static rsRetVal setUmask(void __attribute__((unused)) *pVal, int iUmask)
}
+/* 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];
+
+dbgprintf("userid before drop: %d\n", getuid());
+ res = setuid(iUid);
+dbgprintf("userid after drop: %d\n", getuid());
+ 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);
+}
+
+
/* helper to freeSelectors(), used with llExecFunc() to flush
* pending output. -- rgerhards, 2007-08-02
* We do not need to lock the action object here as the processing
@@ -2807,6 +2832,8 @@ static rsRetVal loadBuildInModules(void)
CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"errormessagestostderr", 0, eCmdHdlrBinary, NULL, &bErrMsgToStderr, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"maxmessagesize", 0, eCmdHdlrSize, setMaxMsgSize, NULL, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"privdroptouser", 0, eCmdHdlrUID, NULL, &uidDropPriv, NULL));
+// CHKiRet(regCfSysLineHdlr((uchar *)"privdroptogroup", 0, eCmdHdlrGID, doDropPrivGroup, NULL, NULL));
/* now add other modules handlers (we should work on that to be able to do it in ClassInit(), but so far
* that is not possible). -- rgerhards, 2008-01-28
@@ -2900,8 +2927,20 @@ static rsRetVal mainThread()
}
/* Send a signal to the parent so it can terminate.
*/
- if (myPid != ppid)
- kill (ppid, SIGTERM);
+ if(myPid != ppid)
+ kill(ppid, SIGTERM);
+
+
+ /* If instructed to do so, we now drop privileges. Note that this is not 100% secure,
+ * because inputs and 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(uidDropPriv != 0) {
+ doDropPrivUid(uidDropPriv);
+ }
/* END OF INTIALIZATION
* ... but keep in mind that we might do a restart and thus init() might
@@ -3520,11 +3559,14 @@ int realMain(int argc, char **argv)
/* process compatibility mode settings */
- if(iCompatibilityMode < 3) {
+ if(iCompatibilityMode < 4) {
errmsg.LogError(0, NO_ERRCODE, "WARNING: rsyslogd is running in compatibility mode. Automatically "
"generated config directives may interfer with your rsyslog.conf settings. "
- "We suggest upgrading your config and adding -c3 as the first "
+ "We suggest upgrading your config and adding -c4 as the first "
"rsyslogd option.");
+ }
+
+ if(iCompatibilityMode < 3) {
if(MarkInterval > 0) {
legacyOptsEnq((uchar *) "ModLoad immark");
snprintf((char *) legacyConfLine, sizeof(legacyConfLine), "MarkMessagePeriod %d", MarkInterval);
--
cgit
From dc478db1ca80ef222f83985b539dfec1c66063e2 Mon Sep 17 00:00:00 2001
From: Rainer Gerhards
Date: Wed, 26 Nov 2008 14:17:36 +0100
Subject: added ability to drop privileges
Added $PrivDropToGroup, $PrivDropToUser, $PrivDropToGroupID,
$PrivDropToUserID config directives to enable dropping privileges.
This is an effort to provide a security enhancement. For the limits of this
approach, see http://wiki.rsyslog.com/index.php/Security
---
ChangeLog | 6 +++++
configure.ac | 2 +-
doc/Makefile.am | 1 +
doc/droppriv.html | 60 ++++++++++++++++++++++++++++++++++++++++++++
doc/manual.html | 2 +-
doc/rsyslog_conf_global.html | 5 ++++
tools/syslogd.c | 43 ++++++++++++++++++++++++++++---
7 files changed, 114 insertions(+), 5 deletions(-)
create mode 100644 doc/droppriv.html
diff --git a/ChangeLog b/ChangeLog
index 70ad7e1f..fe8df1fc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,10 @@
---------------------------------------------------------------------------
+Version 4.1.1 [DEVEL] (rgerhards), 2008-11-??
+- added $PrivDropToGroup, $PrivDropToUser, $PrivDropToGroupID,
+ $PrivDropToUserID config directives to enable dropping privileges.
+ This is an effort to provide a security enhancement. For the limits of this
+ approach, see http://wiki.rsyslog.com/index.php/Security
+---------------------------------------------------------------------------
Version 4.1.0 [DEVEL] (rgerhards), 2008-11-18
********************************* WARNING *********************************
diff --git a/configure.ac b/configure.ac
index 981ef193..8eecf2ab 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.61)
-AC_INIT([rsyslog],[4.1.0],[rsyslog@lists.adiscon.com])
+AC_INIT([rsyslog],[4.1.1],[rsyslog@lists.adiscon.com])
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([ChangeLog])
AC_CONFIG_HEADERS([config.h])
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 5c2f5313..b58f813b 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -5,6 +5,7 @@ html_files = \
features.html \
generic_design.html \
expression.html \
+ droppriv.html \
history.html \
how2help.html \
install.html \
diff --git a/doc/droppriv.html b/doc/droppriv.html
new file mode 100644
index 00000000..7293e872
--- /dev/null
+++ b/doc/droppriv.html
@@ -0,0 +1,60 @@
+
+dropping privileges in rsyslog
+
+
+Dropping privileges in rsyslog
+Available since: 4.1.1
+Description:
+
+Rsyslogd provides the ability to drop privileges by
+impersonating as another user and/or group after startup.
+
+
Please note that due to POSIX standards, rsyslogd always needs to start
+up as root if there is a listener who must bind to a network port below 1024.
+For example, the UDP listener usually needs to listen to 514 and as such
+rsyslogd needs to start up as root.
+
+
If you do not need this functionality, you can start rsyslog directly as an ordinary
+user. That is probably the safest way of operations. However, if a startup as
+root is required, you can use the $PrivDropToGroup and $PrivDropToUser config
+directives to specify a group and/or user that rsyslogd should drop to after initialization.
+Once this happend, the daemon runs without high privileges (depending, of
+course, on the permissions of the user account you specified).
+
There is some additional information available in the
+rsyslog wiki.
+
Configuration Directives:
+
+- $PrivDropToUser
+Name of the user rsyslog should run under after startup. Please note that
+this user is looked up in the system tables. If the lookup fails, privileges are
+NOT dropped. Thus it is advisable to use the less convenient $PrivDropToUserID directive.
+If the user id can be looked up, but can not be set, rsyslog aborts.
+
+
+- $PrivDropToUserID
+Much the same as $PrivDropToUser, except that a numerical user id instead of a name
+is specified.Thus, privilege drop will always happen.
+rsyslogd aborts.
+ - $PrivDropToGroup
+Name of the group rsyslog should run under after startup. Please note that
+this user is looked up in the system tables. If the lookup fails, privileges are
+NOT dropped. Thus it is advisable to use the less convenient $PrivDropToGroupID directive.
+Note that all supplementary groups are removed from the process if $PrivDropToGroup is
+specified.
+If the group id can be looked up, but can not be set, rsyslog aborts.
+
+
+- $PrivDropToGroupID
+Much the same as $PrivDropToGroup, except that a numerical group id instead of a name
+is specified. Thus, privilege drop will always happen.
+
+[rsyslog.conf overview]
+[manual index] [rsyslog site]
+This documentation is part of the rsyslog
+project.
+Copyright © 2008 by Rainer
+Gerhards and
+Adiscon.
+Released under the GNU GPL version 3 or higher.
+
+
diff --git a/doc/manual.html b/doc/manual.html
index e208755d..8210165f 100644
--- a/doc/manual.html
+++ b/doc/manual.html
@@ -16,7 +16,7 @@ relay chains while at the same time being very easy to setup for the
novice user. And as we know what enterprise users really need, there is
also professional
rsyslog support available directly from the source!
-This documentation is for version 4.1.0 (devel branch) of rsyslog.
+
This documentation is for version 4.1.1 (devel branch) of rsyslog.
Visit the rsyslog status page to obtain current
version information and project status.
If you like rsyslog, you might
diff --git a/doc/rsyslog_conf_global.html b/doc/rsyslog_conf_global.html
index bc618dd0..d02245e3 100644
--- a/doc/rsyslog_conf_global.html
+++ b/doc/rsyslog_conf_global.html
@@ -200,6 +200,11 @@ time calls should usually be acceptable. The default value is two, because we ha
seen that even without optimization the kernel often returns twice the identical time.
You can set this value as high as you like, but do so at your own risk. The higher
the value, the less precise the timestamp.
+$PrivDropToGroup
+$PrivDropToGroupID
+$PrivDropToUser
+$PrivDropToUserID
+
$UMASK
Where <size_nbr> is specified above,
diff --git a/tools/syslogd.c b/tools/syslogd.c
index 51ce1830..d132d139 100644
--- a/tools/syslogd.c
+++ b/tools/syslogd.c
@@ -82,6 +82,7 @@
#include
#include
#include
+#include
#if HAVE_SYS_TIMESPEC_H
# include
@@ -273,6 +274,7 @@ static int bHaveMainQueue = 0;/* set to 1 if the main queue - in queueing mode -
* queueing mode (mode DIRECT!), then this is set to 0.
*/
static int uidDropPriv = 0; /* user-id to which priveleges should be dropped to (AFTER init()!) */
+static int gidDropPriv = 0; /* group-id to which priveleges should be dropped to (AFTER init()!) */
extern int errno;
@@ -2064,6 +2066,34 @@ static rsRetVal setUmask(void __attribute__((unused)) *pVal, int iUmask)
}
+/* 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
@@ -2074,9 +2104,7 @@ static void doDropPrivUid(int iUid)
int res;
uchar szBuf[1024];
-dbgprintf("userid before drop: %d\n", getuid());
res = setuid(iUid);
-dbgprintf("userid after drop: %d\n", getuid());
if(res) {
/* if we can not set the userid, this is fatal, so let's unconditionally abort */
perror("could not set requested userid");
@@ -2833,7 +2861,9 @@ static rsRetVal loadBuildInModules(void)
CHKiRet(regCfSysLineHdlr((uchar *)"errormessagestostderr", 0, eCmdHdlrBinary, NULL, &bErrMsgToStderr, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"maxmessagesize", 0, eCmdHdlrSize, setMaxMsgSize, NULL, NULL));
CHKiRet(regCfSysLineHdlr((uchar *)"privdroptouser", 0, eCmdHdlrUID, NULL, &uidDropPriv, NULL));
-// CHKiRet(regCfSysLineHdlr((uchar *)"privdroptogroup", 0, eCmdHdlrGID, doDropPrivGroup, NULL, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"privdroptouserid", 0, eCmdHdlrInt, NULL, &uidDropPriv, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"privdroptogroup", 0, eCmdHdlrGID, NULL, &gidDropPriv, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"privdroptogroupid", 0, eCmdHdlrGID, NULL, &gidDropPriv, NULL));
/* now add other modules handlers (we should work on that to be able to do it in ClassInit(), but so far
* that is not possible). -- rgerhards, 2008-01-28
@@ -2938,10 +2968,17 @@ static rsRetVal mainThread()
* drop privileges at all. Doing it correctly, requires a change in architecture, which
* we should do over time. TODO -- rgerhards, 2008-11-19
*/
+ if(gidDropPriv != 0) {
+ doDropPrivGid(gidDropPriv);
+ glbl.SetHUPisRestart(0); /* we can not do restart-type HUPs with dropped privs */
+ }
+
if(uidDropPriv != 0) {
doDropPrivUid(uidDropPriv);
+ glbl.SetHUPisRestart(0); /* we can not do restart-type HUPs with dropped privs */
}
+
/* END OF INTIALIZATION
* ... but keep in mind that we might do a restart and thus init() might
* be called again. If that happens, we must shut down the worker thread,
--
cgit