Hi, I've updated the switch user patch. The user to switch to is a build time define now to prevent vdr vom accidently running under the wrong uid. Patches for 1.2.6 and 1.3.17 attached. cu Ludwig -- (o_ Ludwig.Nussel@gmx.de //\ V_/_ PGP Key ID: FF8135CE
only in patch2: Index: vdr-1.2.6/Makefile =================================================================== --- vdr-1.2.6.orig/Makefile +++ vdr-1.2.6/Makefile @@ -55,7 +55,7 @@ DEFINES += -DPLUGINDIR=\"$(PLUGINLIBDIR) ifdef DEBUG_OSD DEFINES += -DDEBUG_OSD -NCURSESLIB = -lncurses +LIBS += -lncurses endif ifdef VFAT @@ -63,6 +63,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.c fontosd.c fontsmallfix.c fontsmallosd.c @echo "font files created." @@ -84,7 +95,7 @@ $(DEPFILE): Makefile # The main program: vdr: $(OBJS) $(DTVLIB) - $(CXX) $(CXXFLAGS) -rdynamic $(OBJS) $(NCURSESLIB) -ljpeg -lpthread -ldl $(LIBDIRS) $(DTVLIB) -o vdr + $(CXX) $(CXXFLAGS) -rdynamic $(OBJS) $(LIBS) -ljpeg -lpthread -ldl $(LIBDIRS) $(DTVLIB) -o vdr # The font files: Index: vdr-1.2.6/vdr.c =================================================================== --- vdr-1.2.6.orig/vdr.c +++ vdr-1.2.6/vdr.c @@ -31,6 +31,14 @@ #include <stdlib.h> #include <termios.h> #include <unistd.h> +#ifdef VDR_USER +#include <pwd.h> +#include <grp.h> +#ifdef WITH_CAPABILITIES +#include <sys/capability.h> +#include <sys/prctl.h> +#endif +#endif #include "audio.h" #include "channels.h" #include "config.h" @@ -77,6 +85,110 @@ 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 passwd *user = NULL; + + if(!username) return 0; + + errno = 0; + user = getpwnam(username); + if(!user) + { + fprintf(stderr,"invalid user %s: %s\n",username,errno?strerror(errno):"user does not exist"); + endpwent(); + return 1; + } + endpwent(); + if(groupname) + { + errno = 0; + grp = getgrnam(groupname); + if(!grp) + { + 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: @@ -223,6 +335,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.2.6/Make.config.template =================================================================== --- vdr-1.2.6.orig/Make.config.template +++ vdr-1.2.6/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
only in patch2: Index: vdr-1.3.17/Makefile =================================================================== --- vdr-1.3.17.orig/Makefile +++ vdr-1.3.17/Makefile @@ -73,7 +73,18 @@ DEFINES += -DPLUGINDIR=\"$(PLUGINLIBDIR) ifdef VFAT # for people who want their video directory on a VFAT partition -DEFINES += -DVFAT +DEFINES += -DVFALDT +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 @@ -102,7 +113,7 @@ $(DEPFILE): Makefile # The main program: vdr: $(OBJS) $(SILIB) - $(CXX) $(CXXFLAGS) -rdynamic $(OBJS) $(NCURSESLIB) -ljpeg -lpthread -ldl $(LIBDIRS) $(SILIB) -o vdr + $(CXX) $(CXXFLAGS) -rdynamic $(OBJS) $(LIBS) -ljpeg -lpthread -ldl $(LIBDIRS) $(SILIB) -o vdr # The font files: Index: vdr-1.3.17/vdr.c =================================================================== --- vdr-1.3.17.orig/vdr.c +++ vdr-1.3.17/vdr.c @@ -31,6 +31,14 @@ #include <stdlib.h> #include <termios.h> #include <unistd.h> +#ifdef VDR_USER +#include <pwd.h> +#include <grp.h> +#ifdef WITH_CAPABILITIES +#include <sys/capability.h> +#include <sys/prctl.h> +#endif +#endif #include "audio.h" #include "channels.h" #include "config.h" @@ -85,6 +93,110 @@ 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 passwd *user = NULL; + + if(!username) return 0; + + errno = 0; + user = getpwnam(username); + if(!user) + { + fprintf(stderr,"invalid user %s: %s\n",username,errno?strerror(errno):"user does not exist"); + endpwent(); + return 1; + } + endpwent(); + if(groupname) + { + errno = 0; + grp = getgrnam(groupname); + if(!grp) + { + 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[]) { #ifdef _CS_GNU_LIBPTHREAD_VERSION @@ -253,6 +365,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.17/Make.config.template =================================================================== --- vdr-1.3.17.orig/Make.config.template +++ vdr-1.3.17/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
Attachment:
pgp00015.pgp
Description: PGP signature