Submitted By: Jim Gifford (jim at linuxfromscratch dot org)
Date: 2004-05-06
Initial Package Version: 1.4.1
Origin: Archaic 
Upstream Status: Unknown
Description: Allows syslog and klog to use a specific user other than root
 
diff -Nur sysklogd-1.4.1.orig/klogd.8 sysklogd-1.4.1/klogd.8
--- sysklogd-1.4.1.orig/klogd.8	Sun Mar 11 20:35:51 2001
+++ sysklogd-1.4.1/klogd.8	Fri Mar 16 14:11:38 2001
@@ -3,6 +3,7 @@
 .\" Sun Jul 30 01:35:55 MET: Martin Schulze: Updates
 .\" Sun Nov 19 23:22:21 MET: Martin Schulze: Updates
 .\" Mon Aug 19 09:42:08 CDT 1996: Dr. G.W. Wettstein: Updates
+.\" Thu Feb 17 2000: Chris Wing: Unprivileged klogd feature
 .\"
 .TH KLOGD 8 "21 August, 1999" "Version 1.4" "Linux System Administration"
 .SH NAME
@@ -17,7 +18,11 @@
 .RB [ " \-f "
 .I fname
 ]
+.RB [ " \-u "
+.I username
+]
 .RB [ " \-iI " ]
+.RB [ " \-r " ]
 .RB [ " \-n " ]
 .RB [ " \-o " ]
 .RB [ " \-p " ]
@@ -46,11 +51,24 @@
 .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. This is useful if you are paranoid about how well we wrote
+this program.
+.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
 daemon to reload the kernel module symbols.  The \-I switch signals for a
 reload of both the static kernel symbols and the kernel module symbols.
+.TP
+.B "\-r"
+Reset kernel logging. You should run
+.B klogd
+with this argument after killing the daemon, if you run the daemon as a non-
+privileged user. This is because
+.B klogd
+will be unable to reset kernel logging automatically in that case.
 .TP
 .B "\-n"
 Avoid auto-backgrounding.  This is needed especially if the
diff -Nur sysklogd-1.4.1.orig/klogd.c sysklogd-1.4.1/klogd.c
--- sysklogd-1.4.1.orig/klogd.c	Sun Mar 11 20:40:10 2001
+++ sysklogd-1.4.1/klogd.c	Fri Mar 16 14:38:52 2001
@@ -275,6 +275,10 @@
 #define ksyslog klogctl
 #endif
 
+/* Support for running as an unprivileged user */
+#include <pwd.h>
+#include <grp.h>
+
 #define LOG_BUFFER_SIZE 4096
 #define LOG_LINE_LENGTH 1000
 
@@ -308,6 +312,9 @@
 int debugging = 0;
 int symbols_twice = 0;
 
+int drop_privileges = 0;
+uid_t server_uid = 0;
+gid_t server_gid = 0;
 
 /* Function prototypes. */
 extern int ksyslog(int type, char *buf, int len);
@@ -994,7 +1001,7 @@
 	chdir ("/");
 #endif
 	/* Parse the command-line. */
-	while ((ch = getopt(argc, argv, "c:df:iIk:nopsvx2")) != EOF)
+	while ((ch = getopt(argc, argv, "c:df:u:iIk:noprsvx2")) != EOF)
 		switch((char)ch)
 		{
 		    case '2':		/* Print lines with symbols twice. */
@@ -1010,6 +1017,31 @@
 			output = optarg;
 			use_output++;
 			break;
+		    case 'u':           /* Run as this user */
+			if (optarg) {
+			    struct passwd *pwd;
+
+			    pwd = getpwnam(optarg);
+			    if (!pwd) {
+				fprintf(stderr, "Failed to look up user %s " \
+				"to switch to. Terminating.\n", optarg);
+			    exit(1);
+			    }
+
+			drop_privileges = 1;
+			server_uid = pwd->pw_uid;
+			server_gid = pwd->pw_gid;
+			} else {
+			    fprintf(stderr, "Must specify user name along " \
+			                    "with -u option.\n");
+			    exit(1);
+			}
+			break;
+		    case 'r':           /* Reset logging */
+			Syslog(LOG_INFO, "Resetting kernel logging.");
+			CloseLogSrc();
+			exit(0);
+			break;
 		    case 'i':		/* Reload module symbols. */
 			SignalDaemon(SIGUSR1);
 			return(0);
@@ -1161,6 +1193,13 @@
 	if (symbol_lookup) {
 		InitKsyms(symfile);
 		InitMsyms();
+	}
+
+	/* Drop privileges if a user name was specified on the command line */
+	if (drop_privileges) {
+		setgroups(0, NULL);
+		setgid(server_gid);
+		setuid(server_uid);
 	}
 
         /* The main loop. */
diff -Nur sysklogd-1.4.1.orig/sysklogd.8 sysklogd-1.4.1/sysklogd.8
--- sysklogd-1.4.1.orig/sysklogd.8	Sun Mar 11 20:35:51 2001
+++ sysklogd-1.4.1/sysklogd.8	Fri Mar 16 14:40:16 2001
@@ -29,6 +29,9 @@
 .RB [ " \-s "
 .I domainlist
 ]
+.RB [ " \-u"
+.IB username
+]
 .RB [ " \-v " ]
 .LP
 .SH DESCRIPTION
@@ -149,6 +152,22 @@
 is specified and the host logging resolves to satu.infodrom.north.de
 no domain would be cut, you will have to specify two domains like:
 .BR "\-s north.de:infodrom.north.de" .
+.TP
+.BI "\-u " "username"
+This causes the
+.B syslogd
+daemon to become the named user before starting up logging. This
+option is useful if you are paranoid about how well we wrote this
+program.
+
+Note that when this option is in use,
+.B syslogd
+will open all log files as root when the daemon is first started;
+however, after a
+.B SIGHUP
+the files will be reopened as the non-privileged user. You should
+take this into account when deciding the ownership of the log
+files.
 .TP
 .B "\-v"
 Print version and exit.
diff -Nur sysklogd-1.4.1.orig/syslogd.c sysklogd-1.4.1/syslogd.c
--- sysklogd-1.4.1.orig/syslogd.c	Sun Mar 11 20:40:10 2001
+++ sysklogd-1.4.1/syslogd.c	Fri Mar 16 14:44:02 2001
@@ -500,6 +500,10 @@
 #include <paths.h>
 #endif
 
+/* Support for running syslogd as non-root user */
+#include <pwd.h>
+#include <grp.h>
+
 #ifndef UTMP_FILE
 #ifdef UTMP_FILENAME
 #define UTMP_FILE UTMP_FILENAME
@@ -735,6 +739,7 @@
 char	**LocalHosts = NULL;	/* these hosts are logged with their hostname */
 int	NoHops = 1;		/* Can we bounce syslog messages through an
 				   intermediate host. */
+char	*server_user = NULL;	/* user name to run server as, instead of root */
 
 extern	int errno;
 
@@ -829,7 +834,7 @@
 		funix[i]  = -1;
 	}
 
-	while ((ch = getopt(argc, argv, "a:dhf:l:m:np:rs:v")) != EOF)
+	while ((ch = getopt(argc, argv, "a:dhf:l:m:np:rs:u:v")) != EOF)	
 		switch((char)ch) {
 		case 'a':
 			if (nfunix < MAXFUNIX)
@@ -874,6 +879,15 @@
 			}
 			StripDomains = crunch_list(optarg);
 			break;
+		case 'u':
+			if (optarg)
+				server_user = strdup(optarg);
+			else {
+				fprintf (stderr, "Must specify user name " \
+				                 "along with -u option.\n");
+				exit (1);
+			}
+			break;
 		case 'v':
 			printf("syslogd %s.%s\n", VERSION, PATCHLEVEL);
 			exit (0);
@@ -1020,6 +1034,28 @@
 	if (getpid() != ppid)
 		kill (ppid, SIGTERM);
 #endif
+	/*
+	* Drop privileges if a user name was specified on
+	* the command line.
+	*/
+	if (server_user) {
+		struct passwd *pwd;
+
+		pwd = getpwnam(server_user);
+		if (!pwd) {
+			dprintf("Failed to look up user %s.\n", server_user);
+			exit(1);
+		}
+
+	/* initgroups should not require the stupid "extra group" thingy */
+		if (initgroups(server_user, pwd->pw_gid)) {
+			dprintf("Failed to set groups for user %s.\n", server_user);
+			exit(1);
+		}
+
+		setgid(pwd->pw_gid);
+		setuid(pwd->pw_uid);
+	}
 
 	/* Main loop begins here. */
 	for (;;) {
@@ -1175,7 +1211,7 @@
 int usage()
 {
 	fprintf(stderr, "usage: syslogd [-drvh] [-l hostlist] [-m markinterval] [-n] [-p path]\n" \
-		" [-s domainlist] [-f conffile]\n");
+		" [-s domainlist] [-f conffile] [-u username]\n");
 	exit(1);
 }
 
