mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
When started as user 'root' VDR now switches to a lesser privileged user id, keeping the capability to set the system time
This commit is contained in:
parent
c65133979f
commit
89df449715
@ -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'
|
||||
|
9
HISTORY
9
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.
|
||||
|
13
INSTALL
13
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:
|
||||
-------------------
|
||||
|
||||
|
4
Makefile
4
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
|
||||
|
8
runvdr
8
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"
|
||||
|
9
vdr.1
9
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.
|
||||
|
91
vdr.c
91
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():
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user