only in patch2: Index: vdr-1.3.27/Makefile =================================================================== --- vdr-1.3.27.orig/Makefile +++ vdr-1.3.27/Makefile @@ -82,6 +82,17 @@ ifdef VFAT DEFINES += -DVFAT endif +ifdef VDR_USER +DEFINES += -DVDR_USER=\"$(VDR_USER)\" +ifdef VDR_GROUP +DEFINES += -DVDR_GROUP=\"$(VDR_GROUP)\" +endif +ifdef WITH_CAPABILITIES +DEFINES += -DWITH_CAPABILITIES +LIBS += -lcap +endif +endif + all: vdr font: genfontfile\ fontfix-iso8859-1.c fontosd-iso8859-1.c fontsml-iso8859-1.c\ Index: vdr-1.3.27/vdr.c =================================================================== --- vdr-1.3.27.orig/vdr.c +++ vdr-1.3.27/vdr.c @@ -31,6 +31,14 @@ #include #include #include +#ifdef VDR_USER +#include +#include +#ifdef WITH_CAPABILITIES +#include +#include +#endif +#endif #include "audio.h" #include "channels.h" #include "config.h" @@ -85,6 +93,114 @@ static void Watchdog(int signum) exit(1); } +#ifdef VDR_USER +// switch user and group uid +// taken from startproc by Werner Fink +static int su(const char* username, const char* groupname) +{ + gid_t ngid = 0; + struct group* grp = NULL; + struct group grpbuf; + struct passwd *user = NULL; + struct passwd userbuf; + int result; + char buf[1024]; + + if(!username) return 0; + + errno = 0; + result = getpwnam_r(username, &userbuf, buf, sizeof(buf), &user); + if (result != 0 || user != &userbuf) + { + fprintf(stderr,"invalid user %s: %s\n",username,errno?strerror(errno):"user does not exist"); + endpwent(); + return 1; + } + endpwent(); + if(groupname) + { + errno = 0; + result = getgrnam_r(groupname, &grpbuf, buf, sizeof(buf), &grp); + if (result != 0 || grp != &grpbuf) + { + fprintf(stderr,"invalid group %s: %s\n",groupname,errno?strerror(errno):"group does not exist"); + endgrent(); + return 1; + } + endgrent(); + } + + ngid = user->pw_gid; + if (grp) + ngid = grp->gr_gid; + + if (setgid(ngid) < 0) + { + fprintf(stderr,"cannot set group id %u: %s\n", (unsigned int)ngid, strerror(errno)); + return 1; + } + if (!getuid()) + { + if (initgroups(user->pw_name, ngid) < 0) + { + fprintf(stderr,"cannot set supplemental group ids for user %s: %s\n", + user->pw_name, strerror(errno)); + return 1; + } + } + if (setuid(user->pw_uid) < 0) + { + fprintf(stderr,"cannot set user id %u: %s\n", + (unsigned int)user->pw_uid, strerror(errno)); + return 1; + } + return 0; +} + +#ifdef WITH_CAPABILITIES +// drop all capabilities except cap_sys_time +static int set_cap_sys_time(void) +{ + cap_t caps; + + caps = cap_from_text("= cap_sys_time=ep"); + if(!caps) + { + perror("cap_from_text"); + return -1; + } + + if( cap_set_proc(caps) == -1 ) + { + perror("cap_set_proc"); + cap_free(caps); + return -1; + } + + cap_free(caps); + + return 0; +} + +// keep capabilities during setuid() +static inline int set_keepcaps(void) +{ + return prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0); +} + +static inline int set_nokeepcaps(void) +{ + return prctl(PR_SET_KEEPCAPS, 0, 0, 0, 0); +} +#else +static inline int return0() { return 0; } +#define printcap() return0() +#define set_cap_sys_time() return0() +#define set_keepcaps() return0() +#define set_nokeepcaps() return0() +#endif // WITH_CAPABILITIES +#endif // VDR_USER + int main(int argc, char *argv[]) { // Save terminal settings: @@ -234,6 +350,23 @@ int main(int argc, char *argv[]) } } +#ifdef VDR_USER +# ifndef VDR_GROUP +# define VDR_GROUP NULL +# endif + + if(set_keepcaps() != 0) + return 2; + + if (su(VDR_USER, VDR_GROUP) != 0) + return 2; + + if(set_nokeepcaps() != 0) + return 2; + + set_cap_sys_time(); +#endif + // Help and version info: if (DisplayHelp || DisplayVersion) { Index: vdr-1.3.27/Make.config.template =================================================================== --- vdr-1.3.27.orig/Make.config.template +++ vdr-1.3.27/Make.config.template @@ -25,3 +25,13 @@ BINDIR = /usr/local/bin PLUGINDIR= ./PLUGINS PLUGINLIBDIR= $(PLUGINDIR)/lib VIDEODIR = /video + +## define if you want vdr to not run as root +#VDR_USER = vdr + +## optionally switch to a specific group. Default: group $VDR_USER is in +#VDR_GROUP = video + +## use capabilities to be able to set the clock even though not running as +## root. Requires libcap. +#WITH_CAPABILITIES = 1