]> git.ipfire.org Git - thirdparty/chrony.git/commitdiff
Linux capabilities support
authorMiroslav Lichvar <mlichvar@redhat.com>
Wed, 5 Nov 2008 23:50:48 +0000 (23:50 +0000)
committerRichard P. Curnow <rc@rc0.org.uk>
Wed, 5 Nov 2008 23:50:48 +0000 (23:50 +0000)
Attached is a patch adding a linux capabilities support to chronyd. It
adds -u option which can be used to specify the user which chronyd
should switch to.

chrony.texi
chronyd.8
configure
main.c
sys.c
sys.h
sys_linux.c
sys_linux.h

index 909a0cc355e1d850fddabb485ea9144d43a97cc7..045f02cd6a5f1b3e37269b54b194520e3c3cfcf9 100644 (file)
@@ -1089,6 +1089,9 @@ to work well, it relies on @code{chronyd} having been able to determine
 accurate statistics for the difference between the real time clock and
 system clock last time the computer was on.
 
+@item -u <user>
+When this option is used, chronyd will drop root privileges to the specified
+user.  So far, it works only on Linux when compiled with capabilities support.
 @item -v
 This option displays @code{chronyd's} version number to the terminal and
 exits.
index 78fbe17589f3f5ecf5d2b35692afc71117db8507..dfc40047c6e11731e8022f93f2331dfb36a50a66 100644 (file)
--- a/chronyd.8
+++ b/chronyd.8
@@ -79,6 +79,10 @@ been able to determine accurate statistics for the difference
 between the real time clock and system clock last time the
 computer was on.
 .TP
+\fB\-u\fR \fIuser\fR
+When this option is used, chronyd will drop root privileges to the specified
+user.  So far, it works only on Linux when compiled with capabilities support.
+.TP
 .B \-v
 This option displays \fBchronyd\fR's version number to the terminal and exits
 
index 2bb2ac0024e9393475481c413e2a8d03e6611ea6..9027b85a8f9b1c373261e7fc8490db8ef7db1ffc 100755 (executable)
--- a/configure
+++ b/configure
@@ -134,6 +134,7 @@ For better control, use the options below.
   --readline-lib-dir=DIR Specify where readline lib directory is
   --with-ncurses-library=DIR Specify where ncurses lib directory is
   --disable-rtc          Don't include RTC even on Linux
+  --enable-linuxcaps     Enable Linux capabilities support
 
 Fine tuning of the installation directories:
   --infodir=DIR          info documentation [PREFIX/info]
@@ -174,6 +175,7 @@ SYSDEFS=""
 # Support for readline (on by default)
 feat_readline=1
 feat_rtc=1
+feat_linuxcaps=0
 readline_lib=""
 readline_inc=""
 ncurses_lib=""
@@ -211,6 +213,9 @@ do
     --disable-rtc)
       feat_rtc=0
     ;;
+    --enable-linuxcaps)
+      feat_linuxcaps=1
+    ;;
     --help | -h )
       usage
       exit 0
@@ -248,6 +253,10 @@ case $SYSTEM in
             EXTRA_OBJECTS+=" rtc_linux.o"
             EXTRA_DEFS+=" -DFEAT_RTC=1"
         fi
+        if [ $feat_linuxcaps -eq 1 ] ; then
+            EXTRA_DEFS+=" -DFEAT_LINUXCAPS=1"
+            EXTRA_LIBS="-lcap"
+        fi
         SYSDEFS="-DLINUX"
         echo "Configuring for " $SYSTEM
         if [ "${MACHINE}" = "alpha" ]; then
diff --git a/main.c b/main.c
index 18312e02868cb00f3d16ade36688313b4dc923d8..ba6e4a95528999424f9aabef61c0d612e9263762 100644 (file)
--- a/main.c
+++ b/main.c
@@ -83,19 +83,19 @@ MAI_CleanupAndExit(void)
     SRC_DumpSources();
   }
 
-  RTC_Finalise();
   MNL_Finalise();
   ACQ_Finalise();
-  CAM_Finalise();
   KEY_Finalise();
   CLG_Finalise();
-  NIO_Finalise();
   NSR_Finalise();
   NCR_Finalise();
   BRD_Finalise();
   SRC_Finalise();
   SST_Finalise();
   REF_Finalise();
+  RTC_Finalise();
+  CAM_Finalise();
+  NIO_Finalise();
   SYS_Finalise();
   SCH_Finalise();
   LCL_Finalise();
@@ -206,6 +206,7 @@ int main
 (int argc, char **argv)
 {
   char *conf_file = NULL;
+  char *user = NULL;
   int debug = 0;
   int do_init_rtc = 0;
   int other_pid;
@@ -220,6 +221,9 @@ int main
       conf_file = *argv;
     } else if (!strcmp("-r", *argv)) {
       reload = 1;
+    } else if (!strcmp("-u", *argv)) {
+      ++argv, --argc;
+      user = *argv;
     } else if (!strcmp("-s", *argv)) {
       do_init_rtc = 1;
     } else if (!strcmp("-v", *argv) || !strcmp("--version",*argv)) {
@@ -269,19 +273,23 @@ int main
   LCL_Initialise();
   SCH_Initialise();
   SYS_Initialise();
+  NIO_Initialise();
+  CAM_Initialise();
+  RTC_Initialise();
+
+  if (user)
+    SYS_DropRoot(user);
+
   REF_Initialise();
   SST_Initialise();
   SRC_Initialise();
   BRD_Initialise();
   NCR_Initialise();
   NSR_Initialise();
-  NIO_Initialise();
   CLG_Initialise();
   KEY_Initialise();
-  CAM_Initialise();
   ACQ_Initialise();
   MNL_Initialise();
-  RTC_Initialise();
 
   /* From now on, it is safe to do finalisation on exit */
   initialised = 1;
diff --git a/sys.c b/sys.c
index 9052cf747c6575ffcab3f8a8fe867b313871d160..048ba4d885ce7a4fdafc3da9c9e42abdfc31cf2e 100644 (file)
--- a/sys.c
+++ b/sys.c
@@ -97,6 +97,14 @@ SYS_Finalise(void)
 }
 
 /* ================================================== */
+
+void SYS_DropRoot(char *user)
+{
+#if defined(LINUX) && defined (FEAT_LINUXCAPS)
+  SYS_Linux_DropRoot(user);
+#endif
+}
+
 /* ================================================== */
 /* ================================================== */
 
diff --git a/sys.h b/sys.h
index 973da423bdf47b53547a8dd4adea225177df961e..50b8e46291f516e70e862dbb77003c832cf2d612 100644 (file)
--- a/sys.h
+++ b/sys.h
@@ -39,4 +39,7 @@ extern void SYS_Initialise(void);
 /* Called at the end of the run to do final clean-up */
 extern void SYS_Finalise(void);
 
+/* Drop root privileges to the specified user */
+extern void SYS_DropRoot(char *user);
+
 #endif /* GOT_SYS_H */
index 137e55b2e8599d054295f5e829c5e8e797962746..65eb563b8030793936ff75134e1778f9f049735c 100644 (file)
 #include <assert.h>
 #include <sys/utsname.h>
 
+#ifdef FEAT_LINUXCAPS
+#include <sys/types.h>
+#include <pwd.h>
+#include <sys/prctl.h>
+#include <sys/capability.h>
+#include <grp.h>
+#endif
+
 #include "localp.h"
 #include "sys_linux.h"
 #include "sched.h"
@@ -831,6 +839,50 @@ SYS_Linux_GetKernelVersion(int *major, int *minor, int *patchlevel)
 
 /* ================================================== */
 
+#ifdef FEAT_LINUXCAPS
+void
+SYS_Linux_DropRoot(char *user)
+{
+  struct passwd *pw;
+  cap_t cap;
+
+  if (user == NULL)
+    return;
+
+  if ((pw = getpwnam(user)) == NULL) {
+    LOG_FATAL(LOGF_SysLinux, "getpwnam(%s) failed", user);
+  }
+
+  if (prctl(PR_SET_KEEPCAPS, 1)) {
+    LOG_FATAL(LOGF_SysLinux, "prcap() failed");
+  }
+  
+  if (setgroups(0, NULL)) {
+    LOG_FATAL(LOGF_SysLinux, "setgroups() failed");
+  }
+
+  if (setgid(pw->pw_gid)) {
+    LOG_FATAL(LOGF_SysLinux, "setgid(%d) failed", pw->pw_gid);
+  }
+
+  if (setuid(pw->pw_uid)) {
+    LOG_FATAL(LOGF_SysLinux, "setuid(%d) failed", pw->pw_uid);
+  }
+
+  if ((cap = cap_from_text("cap_sys_time=ep")) == NULL) {
+    LOG_FATAL(LOGF_SysLinux, "cap_from_text() failed");
+  }
+
+  if (cap_set_proc(cap)) {
+    LOG_FATAL(LOGF_SysLinux, "cap_set_proc() failed");
+  }
+
+  LOG(LOGS_INFO, LOGF_SysLinux, "Privileges dropped to user %s", user);
+}
+#endif
+
+/* ================================================== */
+
 #endif /* LINUX */
 
 /* vim:ts=8
index a17e51e2fef0e330c44e2c233a214f129bb64dc7..53639a5d1e00e37890e862e51e96d28e76d42d74 100644 (file)
@@ -37,4 +37,6 @@ extern void SYS_Linux_Finalise(void);
 
 extern void SYS_Linux_GetKernelVersion(int *major, int *minor, int *patchlevel);
 
+extern void SYS_Linux_DropRoot(char *user);
+
 #endif  /* GOT_SYS_LINUX_H */