Mailing List archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[vdr] [PATCH] su



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


Home | Main Index | Thread Index