summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTORS1
-rw-r--r--HISTORY9
-rw-r--r--INSTALL13
-rw-r--r--Makefile4
-rwxr-xr-xrunvdr8
-rw-r--r--vdr.19
-rw-r--r--vdr.c91
7 files changed, 122 insertions, 13 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 2e977d5e..b9b2e321 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -824,6 +824,7 @@ Ludwig Nussel <ludwig.nussel@web.de>
cThread::Start()
for removing the LOCK_THREAD from the LIRC thread
for making the Makefile patch friendlier
+ for a patch that was used for implementing setting the user id
Thomas Koch <tom@harhar.net>
for his support in keeping the Premiere World channels up to date in 'channels.conf'
diff --git a/HISTORY b/HISTORY
index 1ee135d3..82ce33e0 100644
--- a/HISTORY
+++ b/HISTORY
@@ -3963,7 +3963,7 @@ Video Disk Recorder Revision History
commands may now be executed at any time, and the message will be displayed
(no more "pending message").
-2005-12-30: Version 1.3.38
+2005-12-31: Version 1.3.38
- Fixed handling second audio and Dolby Digital PIDs for encrypted channels
(was broken in version 1.3.37).
@@ -4040,3 +4040,10 @@ Video Disk Recorder Revision History
- Updated the Greek OSD texts (thanks to Dimitrios Dimitrakos).
- Changed all "illegal" to "invalid" in error messages (there's nothing "illegal"
in VDR ;-).
+- When started as user 'root' VDR now switches to a lesser privileged user id,
+ keeping the capability to set the system time (based on a patch from Ludwig
+ Nussel). By default the user id 'vdr' is used, which can be changed through
+ the new command line option '-u'. Note that for security reasons VDR will no
+ longer run as user 'root' (unless you explicitly start it with '-u root',
+ but this is not recommended!). The 'runvdr' script has been changed to
+ use the '-u' option.
diff --git a/INSTALL b/INSTALL
index 540b45f2..8290c259 100644
--- a/INSTALL
+++ b/INSTALL
@@ -132,6 +132,19 @@ call to the VDR program, be sure to NOT use the '-d' option! Otherwise
VDR will go into 'deamon' mode and the initial program call will return
immediately!
+Setting the system time:
+------------------------
+
+If you want VDR to set the system time according to the data received
+from the transponder, you need to start VDR as user 'root'. VDR will
+then only keep the capability to set the system time, and set its
+user id to a lesser privileged one ('vdr' by default, can be set
+to a different value with the '-u' option).
+You also need to enable the "EPG/Set system time" option in VDR's
+Setup menu, and select a transponder from which you want to receive
+the time in "Use time from transponder". Make sure you select a transponder
+that has a reliable clock - some transponders are quite off.
+
Automatic shutdown:
-------------------
diff --git a/Makefile b/Makefile
index b268a788..5589ce18 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@
# See the main source file 'vdr.c' for copyright information and
# how to reach the author.
#
-# $Id: Makefile 1.79 2005/09/02 14:23:38 kls Exp $
+# $Id: Makefile 1.80 2005/12/31 10:14:33 kls Exp $
.DELETE_ON_ERROR:
@@ -27,7 +27,7 @@ endif
LSIDIR = ./libsi
MANDIR = /usr/local/man
BINDIR = /usr/local/bin
-LIBS = -ljpeg -lpthread -ldl
+LIBS = -ljpeg -lpthread -ldl -lcap
INCLUDES =
PLUGINDIR= ./PLUGINS
diff --git a/runvdr b/runvdr
index 76fd5f08..7fd4d819 100755
--- a/runvdr
+++ b/runvdr
@@ -7,7 +7,7 @@
#
# Set the environment variable VDRUSR to the user id you
# want VDR to run with. If VDRUSR is not set, VDR will run
-# as 'root', which is not necessarily advisable.
+# as user 'vdr'.
#
# Since this script loads the DVB driver, it must be started
# as user 'root'.
@@ -18,11 +18,11 @@
# See the main source file 'vdr.c' for copyright information and
# how to reach the author.
#
-# $Id: runvdr 1.14 2004/11/21 11:30:00 kls Exp $
+# $Id: runvdr 1.15 2005/12/31 13:30:11 kls Exp $
DVBDIR="../DVB/driver"
VDRPRG="./vdr"
-VDRCMD="$VDRPRG -w 60 $*"
+VDRCMD="$VDRPRG -u $VDRUSR -w 60 $*"
LSMOD="`/sbin/lsmod | grep -w '^dvb' | wc -l`"
KILL="/usr/bin/killall -q -TERM"
@@ -33,7 +33,7 @@ if [ $LSMOD -eq 0 ] ; then
fi
while (true) do
- su $VDRUSR -c "$VDRCMD"
+ $VDRCMD
if test $? -eq 0 -o $? -eq 2; then exit; fi
date
echo "restarting VDR"
diff --git a/vdr.1 b/vdr.1
index 54deb51d..43c15dc9 100644
--- a/vdr.1
+++ b/vdr.1
@@ -8,7 +8,7 @@
.\" License as specified in the file COPYING that comes with the
.\" vdr distribution.
.\"
-.\" $Id: vdr.1 1.16 2005/12/30 15:09:01 kls Exp $
+.\" $Id: vdr.1 1.17 2005/12/31 12:55:16 kls Exp $
.\"
.TH vdr 1 "19 Dec 2004" "1.3.18" "Video Disk Recorder"
.SH NAME
@@ -128,6 +128,13 @@ Call \fIcmd\fR to shutdown the computer.
.BI \-t\ tty ,\ \-\-terminal= tty
Set the controlling terminal.
.TP
+.BI \-u\ user ,\ \-\-user= user
+Run as user \fIuser\fR in case vdr was started as user 'root'.
+Starting vdr as 'root' is necessary if the system time shall
+be set from the transponder data, but for security reasons
+during normal operation vdr switches to a lesser privileged
+user id. By default the user 'vdr' is used.
+.TP
.BI \-v\ dir ,\ \-\-video= dir
Use \fIdir\fR as video directory.
The default is \fI/video\fR.
diff --git a/vdr.c b/vdr.c
index 0d22f257..cb4ca566 100644
--- a/vdr.c
+++ b/vdr.c
@@ -22,13 +22,17 @@
*
* The project's page is at http://www.cadsoft.de/vdr
*
- * $Id: vdr.c 1.223 2005/12/30 15:07:47 kls Exp $
+ * $Id: vdr.c 1.224 2005/12/31 13:30:11 kls Exp $
*/
#include <getopt.h>
+#include <grp.h>
#include <locale.h>
+#include <pwd.h>
#include <signal.h>
#include <stdlib.h>
+#include <sys/capability.h>
+#include <sys/prctl.h>
#include <termios.h>
#include <unistd.h>
#include "audio.h"
@@ -72,6 +76,57 @@
static int Interrupted = 0;
+static bool SetUser(const char *UserName)
+{
+ if (UserName) {
+ struct passwd *user = getpwnam(UserName);
+ if (!user) {
+ fprintf(stderr, "vdr: unknown user: '%s'\n", UserName);
+ return false;
+ }
+ if (setgid(user->pw_gid) < 0) {
+ fprintf(stderr, "vdr: cannot set group id %u: %s\n", (unsigned int)user->pw_gid, strerror(errno));
+ return false;
+ }
+ if (initgroups(user->pw_name, user->pw_gid) < 0) {
+ fprintf(stderr, "vdr: cannot set supplemental group ids for user %s: %s\n", user->pw_name, strerror(errno));
+ return false;
+ }
+ if (setuid(user->pw_uid) < 0) {
+ fprintf(stderr, "vdr: cannot set user id %u: %s\n", (unsigned int)user->pw_uid, strerror(errno));
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool SetCapSysTime(void)
+{
+ // drop all capabilities except cap_sys_time
+ cap_t caps = cap_from_text("= cap_sys_time=ep");
+ if (!caps) {
+ fprintf(stderr, "vdr: cap_from_text failed: %s\n", strerror(errno));
+ return false;
+ }
+ if (cap_set_proc(caps) == -1) {
+ fprintf(stderr, "vdr: cap_set_proc failed: %s\n", strerror(errno));
+ cap_free(caps);
+ return false;
+ }
+ cap_free(caps);
+ return true;
+}
+
+static bool SetKeepCaps(bool On)
+{
+ // set keeping capabilities during setuid() on/off
+ if (prctl(PR_SET_KEEPCAPS, On ? 1 : 0, 0, 0, 0) != 0) {
+ fprintf(stderr, "vdr: prctl failed\n");
+ return false;
+ }
+ return true;
+}
+
static void SignalHandler(int signum)
{
if (signum != SIGPIPE) {
@@ -102,11 +157,14 @@ int main(int argc, char *argv[])
// Command line options:
+#define DEFAULTVDRUSER "vdr"
#define DEFAULTSVDRPPORT 2001
#define DEFAULTWATCHDOG 0 // seconds
#define DEFAULTPLUGINDIR PLUGINDIR
#define DEFAULTEPGDATAFILENAME "epg.data"
+ bool StartedAsRoot = false;
+ const char *VdrUser = DEFAULTVDRUSER;
int SVDRPport = DEFAULTSVDRPPORT;
const char *AudioCommand = NULL;
const char *ConfigDirectory = NULL;
@@ -157,6 +215,7 @@ int main(int argc, char *argv[])
{ "record", required_argument, NULL, 'r' },
{ "shutdown", required_argument, NULL, 's' },
{ "terminal", required_argument, NULL, 't' },
+ { "user", required_argument, NULL, 'u' },
{ "version", no_argument, NULL, 'V' },
{ "vfat", no_argument, NULL, 'v' | 0x100 },
{ "video", required_argument, NULL, 'v' },
@@ -165,7 +224,7 @@ int main(int argc, char *argv[])
};
int c;
- while ((c = getopt_long(argc, argv, "a:c:dD:E:g:hl:L:mp:P:r:s:t:v:Vw:", long_options, NULL)) != -1) {
+ while ((c = getopt_long(argc, argv, "a:c:dD:E:g:hl:L:mp:P:r:s:t:u:v:Vw:", long_options, NULL)) != -1) {
switch (c) {
case 'a': AudioCommand = optarg;
break;
@@ -251,6 +310,9 @@ int main(int argc, char *argv[])
return 2;
}
break;
+ case 'u': if (*optarg)
+ VdrUser = optarg;
+ break;
case 'V': DisplayVersion = true;
break;
case 'v' | 0x100:
@@ -273,6 +335,20 @@ int main(int argc, char *argv[])
}
}
+ // Set user id in case we were started as root:
+
+ if (getuid() == 0) {
+ StartedAsRoot = true;
+ if (!SetKeepCaps(true))
+ return 2;
+ if (!SetUser(VdrUser))
+ return 2;
+ if (!SetKeepCaps(false))
+ return 2;
+ if (!SetCapSysTime())
+ return 2;
+ }
+
// Help and version info:
if (DisplayHelp || DisplayVersion) {
@@ -288,12 +364,12 @@ int main(int argc, char *argv[])
" -D NUM, --device=NUM use only the given DVB device (NUM = 0, 1, 2...)\n"
" there may be several -D options (default: all DVB\n"
" devices will be used)\n"
- " -E FILE --epgfile=FILE write the EPG data into the given FILE (default is\n"
+ " -E FILE, --epgfile=FILE write the EPG data into the given FILE (default is\n"
" '%s' in the video directory)\n"
" '-E-' disables this\n"
" if FILE is a directory, the default EPG file will be\n"
" created in that directory\n"
- " -g DIR --grab=DIR write images from the SVDRP command GRAB into the\n"
+ " -g DIR, --grab=DIR write images from the SVDRP command GRAB into the\n"
" given DIR; DIR must be the full path name of an\n"
" existing directory, without any \"..\", double '/'\n"
" or symlinks (default: none, same as -g-)\n"
@@ -316,6 +392,8 @@ int main(int argc, char *argv[])
" -r CMD, --record=CMD call CMD before and after a recording\n"
" -s CMD, --shutdown=CMD call CMD to shutdown the computer\n"
" -t TTY, --terminal=TTY controlling tty\n"
+ " -u USER, --user=USER run as user USER (default: %s); only applicable\n"
+ " if started as root\n"
" -v DIR, --video=DIR use DIR as video directory (default: %s)\n"
" -V, --version print version information and exit\n"
" --vfat encode special characters in recording names to\n"
@@ -328,6 +406,7 @@ int main(int argc, char *argv[])
LIRC_DEVICE,
DEFAULTSVDRPPORT,
RCU_DEVICE,
+ DEFAULTVDRUSER,
VideoDirectory,
DEFAULTWATCHDOG
);
@@ -378,7 +457,7 @@ int main(int argc, char *argv[])
if (DaemonMode) {
if (daemon(1, 0) == -1) {
- fprintf(stderr, "%m\n");
+ fprintf(stderr, "vdr: %m\n");
esyslog("ERROR: %m");
return 2;
}
@@ -392,6 +471,8 @@ int main(int argc, char *argv[])
}
isyslog("VDR version %s started", VDRVERSION);
+ if (StartedAsRoot)
+ isyslog("switched to user '%s'", VdrUser);
// Main program loop variables - need to be here to have them initialized before any EXIT():