http://cvsweb.openwall.com/cgi/cvsweb.cgi/~checkout~/Owl/packages/sysklogd/sysklogd-1.4.2-caen-owl-klogd-drop-root.diff?rev=1.2;content-type=text%2Fplain diff -upk.orig sysklogd-1.4.2.orig/klogd.8 sysklogd-1.4.2/klogd.8 --- sysklogd-1.4.2.orig/klogd.8 2005-03-11 16:12:09 +0000 +++ sysklogd-1.4.2/klogd.8 2005-08-18 14:37:47 +0000 @@ -18,6 +19,12 @@ klogd \- Kernel Log Daemon .RB [ " \-f " .I fname ] +.RB [ " \-u " +.I username +] +.RB [ " \-j " +.I chroot_dir +] .RB [ " \-iI " ] .RB [ " \-n " ] .RB [ " \-o " ] @@ -53,6 +60,20 @@ stderr. .BI "\-f " file Log messages to the specified filename rather than to the syslog facility. .TP +.BI "\-u " username +Tells klogd to become the specified user and drop root privileges before +starting logging. +.TP +.BI "\-j " chroot_dir +Tells klogd to +.BR chroot (2) +into this directory after initializing. +This option is only valid if the \-u option is also used to run klogd +without root privileges. +Note that the use of this option will prevent \-i and \-I from working +unless you set up the chroot directory in such a way that klogd can still +read the kernel module symbols. +.TP .BI "\-i \-I" Signal the currently executing klogd daemon. Both of these switches control the loading/reloading of symbol information. The \-i switch signals the diff -upk.orig sysklogd-1.4.2.orig/klogd.c sysklogd-1.4.2/klogd.c --- sysklogd-1.4.2.orig/klogd.c 2005-08-18 12:29:52 +0000 +++ sysklogd-1.4.2/klogd.c 2005-08-18 14:37:47 +0000 @@ -261,6 +261,8 @@ #include #include #include +#include +#include #include "klogd.h" #include "ksyms.h" #ifndef TESTING @@ -315,6 +317,9 @@ static enum LOGSRC {none, proc, kernel} int debugging = 0; int symbols_twice = 0; +char *server_user = NULL; +char *chroot_dir = NULL; +int log_flags = 0; /* Function prototypes. */ extern int ksyslog(int type, char *buf, int len); @@ -535,8 +540,9 @@ static enum LOGSRC GetKernelLogSrc(void) * First do a stat to determine whether or not the proc based * file system is available to get kernel messages from. */ - if ( use_syscall || - ((stat(_PATH_KLOG, &sb) < 0) && (errno == ENOENT)) ) + if (!server_user && + (use_syscall || + ((stat(_PATH_KLOG, &sb) < 0) && (errno == ENOENT)))) { /* Initialize kernel logging. */ ksyslog(1, NULL, 0); @@ -983,6 +989,27 @@ static void LogProcLine(void) } +static int drop_root(void) +{ + struct passwd *pw; + + if (!(pw = getpwnam(server_user))) return -1; + + if (!pw->pw_uid) return -1; + + if (chroot_dir) { + if (chdir(chroot_dir)) return -1; + if (chroot(".")) return -1; + } + + if (setgroups(0, NULL)) return -1; + if (setgid(pw->pw_gid)) return -1; + if (setuid(pw->pw_uid)) return -1; + + return 0; +} + + int main(argc, argv) int argc; @@ -1000,7 +1027,7 @@ int main(argc, argv) chdir ("/"); #endif /* Parse the command-line. */ - while ((ch = getopt(argc, argv, "c:df:iIk:nopsvx2")) != EOF) + while ((ch = getopt(argc, argv, "c:df:u:j:iIk:nopsvx2")) != EOF) switch((char)ch) { case '2': /* Print lines with symbols twice. */ @@ -1022,6 +1049,10 @@ int main(argc, argv) case 'I': SignalDaemon(SIGUSR2); return(0); + case 'j': /* chroot 'j'ail */ + chroot_dir = optarg; + log_flags |= LOG_NDELAY; + break; case 'k': /* Kernel symbol file. */ symfile = optarg; break; @@ -1037,6 +1068,9 @@ int main(argc, argv) case 's': /* Use syscall interface. */ use_syscall = 1; break; + case 'u': /* Run as this user */ + server_user = optarg; + break; case 'v': printf("klogd %s.%s\n", VERSION, PATCHLEVEL); exit (1); @@ -1045,6 +1079,10 @@ int main(argc, argv) break; } + if (chroot_dir && !server_user) { + fputs("'-j' is only valid with '-u'\n", stderr); + exit(1); + } /* Set console logging level. */ if ( log_level != (char *) 0 ) @@ -1158,7 +1196,7 @@ int main(argc, argv) } } else - openlog("kernel", 0, LOG_KERN); + openlog("kernel", log_flags, LOG_KERN); /* Handle one-shot logging. */ @@ -1191,6 +1229,11 @@ int main(argc, argv) } } + if (server_user && drop_root()) { + syslog(LOG_ALERT, "klogd: failed to drop root"); + Terminate(); + } + /* The main loop. */ while (1) {