I made a quick change to syslogd(8) so that it can drop root
privileges immediately after starting up. It opens up the log
sockets (UNIX and network domains) and writes the PID files
before dropping privs. It drops privs before openning log
files and writing to users. Therefore, you would need to
modify your log file permissions appropriately. As for writing
to users, ttys generally are writeable by group tty. The UID
chosen to run syslogd as should be in this group if this feature
is desired.
We haven't had many syslogd(8) vulnerabilities lately, but one
less daemon running as root seems like a Good Thing. I do not
see any drawbacks from a security point of view. The log files
would have to be owned, or otherwise writeable, by this other
user, but so what. Obviously, I may be missing something.
Any interest in this? Let me know if you try it out and any
successes or failures.
Patches! CURRENT and RELENG_4 version attached. The documentation
is included as a patch to the syslogd(8) man page.
--
Crist J. Clark | cjclark@alum.mit.edu
| cjclark@jhu.edu
http://people.freebsd.org/~cjc/ | cjc@freebsd.org
-------------- next part --------------
Index: src/usr.sbin/syslogd/syslogd.8
==================================================================RCS file:
/ncvs/src/usr.sbin/syslogd/syslogd.8,v
retrieving revision 1.22.2.16
diff -u -r1.22.2.16 syslogd.8
--- src/usr.sbin/syslogd/syslogd.8 12 Mar 2003 22:08:15 -0000 1.22.2.16
+++ src/usr.sbin/syslogd/syslogd.8 4 Jun 2004 19:51:55 -0000
@@ -48,6 +48,7 @@
.Op Fl m Ar mark_interval
.Op Fl P Ar pid_file
.Op Fl p Ar log_socket
+.Op Fl U Ar user
.Sh DESCRIPTION
The
.Nm
@@ -214,6 +215,16 @@
.Dq =>
to
.Dq = .
+.It Fl U Ar user
+Run as
+.Ar user .
+.Ar User
+must be a valid user name.
+This option allows the daemon to drop root privileges, but still open
+privileged sockets as root at start up.
+Note that privileges are dropped before log files are opened and that the
+user must have privileges to write to ttys in order to send messages
+to users.
.It Fl v
Verbose logging. If specified once, the numeric facility and priority are
logged with each locally-written message. If specified more than once,
Index: src/usr.sbin/syslogd/syslogd.c
==================================================================RCS file:
/ncvs/src/usr.sbin/syslogd/syslogd.c,v
retrieving revision 1.59.2.28
diff -u -r1.59.2.28 syslogd.c
--- src/usr.sbin/syslogd/syslogd.c 29 Feb 2004 20:59:19 -0000 1.59.2.28
+++ src/usr.sbin/syslogd/syslogd.c 4 Jun 2004 19:47:22 -0000
@@ -102,6 +102,7 @@
#include <libutil.h>
#include <limits.h>
#include <paths.h>
+#include <pwd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
@@ -334,9 +335,12 @@
sigset_t mask;
pid_t ppid = 1;
socklen_t len;
+ struct passwd *pw;
+ uid_t runAs;
bindhostname = NULL;
- while ((ch = getopt(argc, argv, "46Aa:b:cdf:kl:m:np:P:suv")) != -1)
+ runAs = getuid();
+ while ((ch = getopt(argc, argv, "46Aa:b:cdf:kl:m:np:P:suU:v")) !=
-1)
switch (ch) {
case '4':
family = PF_INET;
@@ -393,6 +397,11 @@
case 'u': /* only log specified priority */
UniquePriority++;
break;
+ case 'U':
+ if ((pw = getpwnam(optarg)) == NULL)
+ errx(1, "could not find user \"%s\"", optarg);
+ runAs = pw->pw_uid;
+ break;
case 'v': /* log facility and priority */
LogFacPri++;
break;
@@ -489,6 +498,16 @@
if (fp != NULL) {
fprintf(fp, "%d\n", getpid());
(void)fclose(fp);
+ }
+
+ if (runAs != getuid()) {
+ if (setuid(runAs) == -1) {
+ (void)snprintf(line, sizeof(line),
+ "failed to change uid to %d\n", runAs);
+ logerror(line);
+ die(0);
+ }
+ dprintf("changed running uid to %d\n", runAs);
}
dprintf("off & running....\n");
-------------- next part --------------
Index: src/usr.sbin/syslogd/syslogd.8
==================================================================RCS file:
/export/freebsd/ncvs/src/usr.sbin/syslogd/syslogd.8,v
retrieving revision 1.50
diff -u -r1.50 syslogd.8
--- src/usr.sbin/syslogd/syslogd.8 8 Sep 2003 19:57:22 -0000 1.50
+++ src/usr.sbin/syslogd/syslogd.8 4 Jun 2004 19:53:11 -0000
@@ -48,6 +48,7 @@
.Op Fl m Ar mark_interval
.Op Fl P Ar pid_file
.Op Fl p Ar log_socket
+.Op Fl U Ar user
.Sh DESCRIPTION
The
.Nm
@@ -219,6 +220,16 @@
.Dq =>
to
.Dq = .
+.It Fl U Ar user
+Run as
+.Ar user .
+.Ar User
+must be a valid user name.
+This option allows the daemon to drop root privileges, but still open
+privileged sockets as root at start up.
+Note that privileges are dropped before log files are opened and that the
+user must have privileges to write to ttys in order to send messages
+to users.
.It Fl v
Verbose logging. If specified once, the numeric facility and priority are
logged with each locally-written message. If specified more than once,
Index: src/usr.sbin/syslogd/syslogd.c
==================================================================RCS file:
/export/freebsd/ncvs/src/usr.sbin/syslogd/syslogd.c,v
retrieving revision 1.128
diff -u -r1.128 syslogd.c
--- src/usr.sbin/syslogd/syslogd.c 30 May 2004 10:34:58 -0000 1.128
+++ src/usr.sbin/syslogd/syslogd.c 4 Jun 2004 16:33:14 -0000
@@ -103,6 +103,7 @@
#include <libutil.h>
#include <limits.h>
#include <paths.h>
+#include <pwd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
@@ -340,9 +341,12 @@
sigset_t mask;
pid_t ppid = 1;
socklen_t len;
+ struct passwd *pw;
+ uid_t runAs;
bindhostname = NULL;
- while ((ch = getopt(argc, argv, "46Aa:b:cdf:kl:m:nop:P:suv")) != -1)
+ runAs = getuid();
+ while ((ch = getopt(argc, argv, "46Aa:b:cdf:kl:m:nop:P:suU:v")) !=
-1)
switch (ch) {
case '4':
family = PF_INET;
@@ -406,6 +410,11 @@
case 'u': /* only log specified priority */
UniquePriority++;
break;
+ case 'U':
+ if ((pw = getpwnam(optarg)) == NULL)
+ errx(1, "could not find user \"%s\"", optarg);
+ runAs = pw->pw_uid;
+ break;
case 'v': /* log facility and priority */
LogFacPri++;
break;
@@ -501,6 +510,16 @@
if (fp != NULL) {
fprintf(fp, "%d\n", getpid());
(void)fclose(fp);
+ }
+
+ if (runAs != getuid()) {
+ if (setuid(runAs) == -1) {
+ (void)snprintf(line, sizeof(line),
+ "failed to change uid to %d\n", runAs);
+ logerror(line);
+ die(0);
+ }
+ dprintf("changed running uid to %d\n", runAs);
}
dprintf("off & running....\n");