[ovs-dev,v2,1/3] lib: add function to switch daemon user at run time
diff mbox

Message ID 1441754258-9868-1-git-send-email-azhou@nicira.com
State Changes Requested
Headers show

Commit Message

Andy Zhou Sept. 8, 2015, 11:17 p.m. UTC
Added function to drop daemon's root privileges at run time by
allowing it to run as a different user. Daemon can still start
running as root. Each daemon's implementation can invoke this
function when it is ready to drop the root privilege.

Future patch will make use of this function.

Signed-off-by: Andy Zhou <azhou@nicira.com>

---
v2 : fix typos and white spaces
---
 lib/daemon-unix.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++++-
 lib/daemon.h      |  9 ++++++++-
 2 files changed, 57 insertions(+), 2 deletions(-)

Comments

Ben Pfaff Sept. 9, 2015, 12:39 a.m. UTC | #1
I see that I reviewed v1 of each patch (sorry!) but I think that my
comments still apply to v2.

Thanks,

Ben.
Andy Zhou Sept. 9, 2015, 6:36 a.m. UTC | #2
On Tue, Sep 8, 2015 at 5:39 PM, Ben Pfaff <blp@nicira.com> wrote:
> I see that I reviewed v1 of each patch (sorry!) but I think that my
> comments still apply to v2.

No worries, I will go over your comments on v1. Thanks for the review.

Patch
diff mbox

diff --git a/lib/daemon-unix.c b/lib/daemon-unix.c
index eb95521..4a2e7b4 100644
--- a/lib/daemon-unix.c
+++ b/lib/daemon-unix.c
@@ -1,5 +1,5 @@ 
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2015 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@ 
 #include "daemon-private.h"
 #include <errno.h>
 #include <fcntl.h>
+#include <grp.h>
 #include <signal.h>
 #include <stdlib.h>
 #include <string.h>
@@ -64,6 +65,13 @@  static int daemonize_fd = -1;
  * it dies due to an error signal? */
 static bool monitor;
 
+/* --user: Only root can use this option. Switch to new uid:gid after
+ * initially running as root.  */
+static bool switch_to_new_user = false;
+static uid_t uid;
+static gid_t gid;
+static char *user = NULL;
+
 static void check_already_running(void);
 static int lock_pidfile(FILE *, int command);
 static pid_t fork_and_clean_up(void);
@@ -684,3 +692,43 @@  should_service_stop(void)
 {
     return false;
 }
+
+void
+daemon_become_new_user(void)
+{
+    if (switch_to_new_user) {
+        /* "Setuid Demystified" by Hao Chen, etc outlines some caveats of
+         * around unix system call setuid() and friends. This implementation
+         * mostly follow the advice given by the paper.  The paper is
+         * published in 2002, so things could have changed.
+         */
+
+        /* Change both real and effective uid and gid will permanently
+         * drop the process' privilege.  "Setuid Demystified" suggested
+         * that calling getuid() after each setuid() call to verify they
+         * are actually set, because checking return code alone is not
+         * sufficient.
+         *
+         * Linux also has per process file system uid, i.e. fsuid. Without
+         * explicitly setting it, it follows the process' effective uid.
+         * This implementation does not explicitly set fsuid for better
+         * portability.  (Although setresuid() is not available on Solaris,
+         * according to the paper above.)   */
+
+        if (setregid(gid, gid) == -1 || getgid() != gid || getegid() != gid) {
+            VLOG_FATAL("%s: fail to switch group to gid as %d, aborting",
+                       pidfile, gid);
+        }
+
+        if (user && initgroups(user, gid) == -1) {
+            VLOG_FATAL("%s: fail to add supplementary group gid %d, aborting",
+                       pidfile, gid);
+        }
+
+        /* Change both real and effective uid and make sure they are set.  */
+        if (setreuid(uid, uid) == -1 || getuid() != uid || geteuid() != uid) {
+            VLOG_FATAL("%s: fail to switch to user %s, aborting",
+                       pidfile, user);
+        }
+    }
+}
diff --git a/lib/daemon.h b/lib/daemon.h
index 959341d..ccf30f8 100644
--- a/lib/daemon.h
+++ b/lib/daemon.h
@@ -1,5 +1,5 @@ 
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2015 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -76,6 +76,7 @@  void set_detach(void);
 void daemon_set_monitor(void);
 void set_no_chdir(void);
 void ignore_existing_pidfile(void);
+void daemon_become_new_user(void);
 pid_t read_pidfile(const char *name);
 #else
 #define DAEMON_OPTION_ENUMS                    \
@@ -117,6 +118,12 @@  pid_t read_pidfile(const char *name);
 
 void control_handler(DWORD request);
 void set_pipe_handle(const char *pipe_handle);
+
+static inline void
+daemon_become_new_user(void)
+{
+    /* Not implemented. */
+}
 #endif /* _WIN32 */
 
 bool get_detach(void);