From be42b4eeea268d1eaee25423fabe3a46836f5b08 Mon Sep 17 00:00:00 2001 From: Miroslav Lichvar Date: Wed, 5 Nov 2008 23:50:48 +0000 Subject: [PATCH] Linux capabilities support 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 | 3 +++ chronyd.8 | 4 ++++ configure | 9 +++++++++ main.c | 20 ++++++++++++++------ sys.c | 8 ++++++++ sys.h | 3 +++ sys_linux.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ sys_linux.h | 2 ++ 8 files changed, 95 insertions(+), 6 deletions(-) diff --git a/chrony.texi b/chrony.texi index 909a0cc..045f02c 100644 --- a/chrony.texi +++ b/chrony.texi @@ -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 +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. diff --git a/chronyd.8 b/chronyd.8 index 78fbe17..dfc4004 100644 --- 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 diff --git a/configure b/configure index 2bb2ac0..9027b85 100755 --- 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 18312e0..ba6e4a9 100644 --- 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 9052cf7..048ba4d 100644 --- 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 973da42..50b8e46 100644 --- 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 */ diff --git a/sys_linux.c b/sys_linux.c index 137e55b..65eb563 100644 --- a/sys_linux.c +++ b/sys_linux.c @@ -39,6 +39,14 @@ #include #include +#ifdef FEAT_LINUXCAPS +#include +#include +#include +#include +#include +#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 diff --git a/sys_linux.h b/sys_linux.h index a17e51e..53639a5 100644 --- a/sys_linux.h +++ b/sys_linux.h @@ -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 */