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()
|
cThread::Start()
|
||||||
for removing the LOCK_THREAD from the LIRC thread
|
for removing the LOCK_THREAD from the LIRC thread
|
||||||
for making the Makefile patch friendlier
|
for making the Makefile patch friendlier
|
||||||
|
for a patch that was used for implementing setting the user id
|
||||||
|
|
||||||
Thomas Koch <tom@harhar.net>
|
Thomas Koch <tom@harhar.net>
|
||||||
for his support in keeping the Premiere World channels up to date in 'channels.conf'
|
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
|
commands may now be executed at any time, and the message will be displayed
|
||||||
(no more "pending message").
|
(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
|
- Fixed handling second audio and Dolby Digital PIDs for encrypted channels
|
||||||
(was broken in version 1.3.37).
|
(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).
|
- Updated the Greek OSD texts (thanks to Dimitrios Dimitrakos).
|
||||||
- Changed all "illegal" to "invalid" in error messages (there's nothing "illegal"
|
- Changed all "illegal" to "invalid" in error messages (there's nothing "illegal"
|
||||||
in VDR ;-).
|
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
|
VDR will go into 'deamon' mode and the initial program call will return
|
||||||
immediately!
|
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:
|
Automatic shutdown:
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
|
4
Makefile
4
Makefile
@ -4,7 +4,7 @@
|
|||||||
# See the main source file 'vdr.c' for copyright information and
|
# See the main source file 'vdr.c' for copyright information and
|
||||||
# how to reach the author.
|
# 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:
|
.DELETE_ON_ERROR:
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ endif
|
|||||||
LSIDIR = ./libsi
|
LSIDIR = ./libsi
|
||||||
MANDIR = /usr/local/man
|
MANDIR = /usr/local/man
|
||||||
BINDIR = /usr/local/bin
|
BINDIR = /usr/local/bin
|
||||||
LIBS = -ljpeg -lpthread -ldl
|
LIBS = -ljpeg -lpthread -ldl -lcap
|
||||||
INCLUDES =
|
INCLUDES =
|
||||||
|
|
||||||
PLUGINDIR= ./PLUGINS
|
PLUGINDIR= ./PLUGINS
|
||||||
|
8
runvdr
8
runvdr
@ -7,7 +7,7 @@
|
|||||||
#
|
#
|
||||||
# Set the environment variable VDRUSR to the user id you
|
# Set the environment variable VDRUSR to the user id you
|
||||||
# want VDR to run with. If VDRUSR is not set, VDR will run
|
# 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
|
# Since this script loads the DVB driver, it must be started
|
||||||
# as user 'root'.
|
# as user 'root'.
|
||||||
@ -18,11 +18,11 @@
|
|||||||
# See the main source file 'vdr.c' for copyright information and
|
# See the main source file 'vdr.c' for copyright information and
|
||||||
# how to reach the author.
|
# 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"
|
DVBDIR="../DVB/driver"
|
||||||
VDRPRG="./vdr"
|
VDRPRG="./vdr"
|
||||||
VDRCMD="$VDRPRG -w 60 $*"
|
VDRCMD="$VDRPRG -u $VDRUSR -w 60 $*"
|
||||||
|
|
||||||
LSMOD="`/sbin/lsmod | grep -w '^dvb' | wc -l`"
|
LSMOD="`/sbin/lsmod | grep -w '^dvb' | wc -l`"
|
||||||
KILL="/usr/bin/killall -q -TERM"
|
KILL="/usr/bin/killall -q -TERM"
|
||||||
@ -33,7 +33,7 @@ if [ $LSMOD -eq 0 ] ; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
while (true) do
|
while (true) do
|
||||||
su $VDRUSR -c "$VDRCMD"
|
$VDRCMD
|
||||||
if test $? -eq 0 -o $? -eq 2; then exit; fi
|
if test $? -eq 0 -o $? -eq 2; then exit; fi
|
||||||
date
|
date
|
||||||
echo "restarting VDR"
|
echo "restarting VDR"
|
||||||
|
9
vdr.1
9
vdr.1
@ -8,7 +8,7 @@
|
|||||||
.\" License as specified in the file COPYING that comes with the
|
.\" License as specified in the file COPYING that comes with the
|
||||||
.\" vdr distribution.
|
.\" 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"
|
.TH vdr 1 "19 Dec 2004" "1.3.18" "Video Disk Recorder"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
@ -128,6 +128,13 @@ Call \fIcmd\fR to shutdown the computer.
|
|||||||
.BI \-t\ tty ,\ \-\-terminal= tty
|
.BI \-t\ tty ,\ \-\-terminal= tty
|
||||||
Set the controlling terminal.
|
Set the controlling terminal.
|
||||||
.TP
|
.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
|
.BI \-v\ dir ,\ \-\-video= dir
|
||||||
Use \fIdir\fR as video directory.
|
Use \fIdir\fR as video directory.
|
||||||
The default is \fI/video\fR.
|
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
|
* 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 <getopt.h>
|
||||||
|
#include <grp.h>
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
|
#include <pwd.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <sys/capability.h>
|
||||||
|
#include <sys/prctl.h>
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include "audio.h"
|
#include "audio.h"
|
||||||
@ -72,6 +76,57 @@
|
|||||||
|
|
||||||
static int Interrupted = 0;
|
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)
|
static void SignalHandler(int signum)
|
||||||
{
|
{
|
||||||
if (signum != SIGPIPE) {
|
if (signum != SIGPIPE) {
|
||||||
@ -102,11 +157,14 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
// Command line options:
|
// Command line options:
|
||||||
|
|
||||||
|
#define DEFAULTVDRUSER "vdr"
|
||||||
#define DEFAULTSVDRPPORT 2001
|
#define DEFAULTSVDRPPORT 2001
|
||||||
#define DEFAULTWATCHDOG 0 // seconds
|
#define DEFAULTWATCHDOG 0 // seconds
|
||||||
#define DEFAULTPLUGINDIR PLUGINDIR
|
#define DEFAULTPLUGINDIR PLUGINDIR
|
||||||
#define DEFAULTEPGDATAFILENAME "epg.data"
|
#define DEFAULTEPGDATAFILENAME "epg.data"
|
||||||
|
|
||||||
|
bool StartedAsRoot = false;
|
||||||
|
const char *VdrUser = DEFAULTVDRUSER;
|
||||||
int SVDRPport = DEFAULTSVDRPPORT;
|
int SVDRPport = DEFAULTSVDRPPORT;
|
||||||
const char *AudioCommand = NULL;
|
const char *AudioCommand = NULL;
|
||||||
const char *ConfigDirectory = NULL;
|
const char *ConfigDirectory = NULL;
|
||||||
@ -157,6 +215,7 @@ int main(int argc, char *argv[])
|
|||||||
{ "record", required_argument, NULL, 'r' },
|
{ "record", required_argument, NULL, 'r' },
|
||||||
{ "shutdown", required_argument, NULL, 's' },
|
{ "shutdown", required_argument, NULL, 's' },
|
||||||
{ "terminal", required_argument, NULL, 't' },
|
{ "terminal", required_argument, NULL, 't' },
|
||||||
|
{ "user", required_argument, NULL, 'u' },
|
||||||
{ "version", no_argument, NULL, 'V' },
|
{ "version", no_argument, NULL, 'V' },
|
||||||
{ "vfat", no_argument, NULL, 'v' | 0x100 },
|
{ "vfat", no_argument, NULL, 'v' | 0x100 },
|
||||||
{ "video", required_argument, NULL, 'v' },
|
{ "video", required_argument, NULL, 'v' },
|
||||||
@ -165,7 +224,7 @@ int main(int argc, char *argv[])
|
|||||||
};
|
};
|
||||||
|
|
||||||
int c;
|
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) {
|
switch (c) {
|
||||||
case 'a': AudioCommand = optarg;
|
case 'a': AudioCommand = optarg;
|
||||||
break;
|
break;
|
||||||
@ -251,6 +310,9 @@ int main(int argc, char *argv[])
|
|||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'u': if (*optarg)
|
||||||
|
VdrUser = optarg;
|
||||||
|
break;
|
||||||
case 'V': DisplayVersion = true;
|
case 'V': DisplayVersion = true;
|
||||||
break;
|
break;
|
||||||
case 'v' | 0x100:
|
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:
|
// Help and version info:
|
||||||
|
|
||||||
if (DisplayHelp || DisplayVersion) {
|
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"
|
" -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"
|
" there may be several -D options (default: all DVB\n"
|
||||||
" devices will be used)\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"
|
" '%s' in the video directory)\n"
|
||||||
" '-E-' disables this\n"
|
" '-E-' disables this\n"
|
||||||
" if FILE is a directory, the default EPG file will be\n"
|
" if FILE is a directory, the default EPG file will be\n"
|
||||||
" created in that directory\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"
|
" given DIR; DIR must be the full path name of an\n"
|
||||||
" existing directory, without any \"..\", double '/'\n"
|
" existing directory, without any \"..\", double '/'\n"
|
||||||
" or symlinks (default: none, same as -g-)\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"
|
" -r CMD, --record=CMD call CMD before and after a recording\n"
|
||||||
" -s CMD, --shutdown=CMD call CMD to shutdown the computer\n"
|
" -s CMD, --shutdown=CMD call CMD to shutdown the computer\n"
|
||||||
" -t TTY, --terminal=TTY controlling tty\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 DIR, --video=DIR use DIR as video directory (default: %s)\n"
|
||||||
" -V, --version print version information and exit\n"
|
" -V, --version print version information and exit\n"
|
||||||
" --vfat encode special characters in recording names to\n"
|
" --vfat encode special characters in recording names to\n"
|
||||||
@ -328,6 +406,7 @@ int main(int argc, char *argv[])
|
|||||||
LIRC_DEVICE,
|
LIRC_DEVICE,
|
||||||
DEFAULTSVDRPPORT,
|
DEFAULTSVDRPPORT,
|
||||||
RCU_DEVICE,
|
RCU_DEVICE,
|
||||||
|
DEFAULTVDRUSER,
|
||||||
VideoDirectory,
|
VideoDirectory,
|
||||||
DEFAULTWATCHDOG
|
DEFAULTWATCHDOG
|
||||||
);
|
);
|
||||||
@ -378,7 +457,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
if (DaemonMode) {
|
if (DaemonMode) {
|
||||||
if (daemon(1, 0) == -1) {
|
if (daemon(1, 0) == -1) {
|
||||||
fprintf(stderr, "%m\n");
|
fprintf(stderr, "vdr: %m\n");
|
||||||
esyslog("ERROR: %m");
|
esyslog("ERROR: %m");
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
@ -392,6 +471,8 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
isyslog("VDR version %s started", VDRVERSION);
|
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():
|
// Main program loop variables - need to be here to have them initialized before any EXIT():
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user