Switch the user/group ID to the specified user in order to drop the root
privileges, but keep the capability to adjust the clock and bind to a
privileged port using the libcap library.

Signed-off-by: Miroslav Lichvar <mlich...@redhat.com>
---
 incdefs.sh | 11 ++++++++-
 makefile   |  4 ++++
 util.c     | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 util.h     |  9 ++++++++
 4 files changed, 90 insertions(+), 1 deletion(-)

diff --git a/incdefs.sh b/incdefs.sh
index 19e620e..9889059 100755
--- a/incdefs.sh
+++ b/incdefs.sh
@@ -19,7 +19,8 @@
 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
 #
-# Look for functional prototypes in the C library.
+# Look for functional prototypes in the C library and development files
+# needed for optional features.
 #
 user_flags()
 {
@@ -50,6 +51,14 @@ user_flags()
                        fi
                done
        done
+
+       # Look for libcap header.
+       for d in $dirs; do
+               if test -a $d/sys/capability.h; then
+                       printf " -DHAVE_LIBCAP"
+                       break
+               fi
+       done
 }
 
 #
diff --git a/makefile b/makefile
index 693e75d..ee4793f 100644
--- a/makefile
+++ b/makefile
@@ -38,6 +38,10 @@ incdefs := $(shell $(srcdir)/incdefs.sh)
 version := $(shell $(srcdir)/version.sh $(srcdir))
 VPATH  = $(srcdir)
 
+ifneq (,$(findstring -DHAVE_LIBCAP,$(incdefs)))
+       LDLIBS += -lcap
+endif
+
 prefix = /usr/local
 sbindir        = $(prefix)/sbin
 mandir = $(prefix)/man
diff --git a/util.c b/util.c
index 73fb37e..85c5e7b 100644
--- a/util.c
+++ b/util.c
@@ -24,6 +24,15 @@
 #include <stdlib.h>
 #include <string.h>
 
+#ifdef HAVE_LIBCAP
+#include <grp.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <sys/prctl.h>
+#include <sys/capability.h>
+#include <unistd.h>
+#endif
+
 #include "address.h"
 #include "print.h"
 #include "sk.h"
@@ -651,3 +660,61 @@ int rate_limited(int interval, time_t *last)
 
        return 0;
 }
+
+int drop_root_privileges(const char *user)
+{
+#ifdef HAVE_LIBCAP
+       struct passwd *pw;
+       cap_t cap;
+#endif
+
+       if (user[0] == '\0')
+               return 0;
+
+#ifdef HAVE_LIBCAP
+       pw = getpwnam(user);
+       if (!pw) {
+               pr_err("failed to get user/group ID of %s", user);
+               return -1;
+       }
+
+       if (prctl(PR_SET_KEEPCAPS, 1)) {
+               pr_err("failed to set KEEPCAPS flag");
+               return -1;
+       }
+
+       if (setgroups(0, NULL)) {
+               pr_err("failed to drop supplementary groups");
+               return -1;
+       }
+
+       if (setgid(pw->pw_gid)) {
+               pr_err("failed to set group ID");
+               return -1;
+       }
+
+       if (setuid(pw->pw_uid)) {
+               pr_err("failed to set user ID");
+               return -1;
+       }
+
+       cap = cap_from_text("cap_sys_time,cap_net_bind_service=ep");
+       if (!cap) {
+               pr_err("failed to initialize capabilities");
+               return -1;
+       }
+
+       if (cap_set_proc(cap)) {
+               pr_err("failed to set process capabilities");
+               cap_free(cap);
+               return -1;
+       }
+
+       cap_free(cap);
+
+       return 0;
+#else
+       pr_err("cannot drop root privileges without libcap");
+       return -1;
+#endif
+}
diff --git a/util.h b/util.h
index 1ab1b3f..79a4f7f 100644
--- a/util.h
+++ b/util.h
@@ -424,4 +424,13 @@ void parray_extend(void ***a, ...);
  */
 int rate_limited(int interval, time_t *last);
 
+/**
+ * Change the user/group ID in order to drop the root privileges. Keep only the
+ * capability to set/adjust the clock and bind to a privileged port.
+ *
+ * @param user      Name of the user.
+ * @return          0 on success, -1 on error.
+ */
+int drop_root_privileges(const char *user);
+
 #endif
-- 
2.17.1


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Linuxptp-devel mailing list
Linuxptp-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxptp-devel

Reply via email to