summaryrefslogtreecommitdiffstats
path: root/support
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2010-01-14 12:24:34 -0500
committerSteve Dickson <steved@redhat.com>2010-01-15 14:55:52 -0500
commite2446fda6e7cdb1b9462162b81b0e50fd6efaf56 (patch)
treef1a6bedafb0fc506cc0cccd8848a13d421a70afb /support
parentd16bd0400fc096ec2fed36d5dfa8620b2370e4d1 (diff)
downloadnfs-utils-e2446fda6e7cdb1b9462162b81b0e50fd6efaf56.tar.gz
nfs-utils-e2446fda6e7cdb1b9462162b81b0e50fd6efaf56.tar.xz
nfs-utils-e2446fda6e7cdb1b9462162b81b0e50fd6efaf56.zip
libnsm.a: retain CAP_NET_BIND when dropping privileges
I'm about to switch the order of listener creation and dropping root privileges. rpc.statd will drop privileges first, then create its listeners. The reason for the new ordering is explained in a subsequent patch. However, for non-TI-RPC builds, rpc_init() needs to use a privileged port to do pmap registrations. For both TI-RPC and non-TI-RPC builds, CAP_NET_BIND is required in case the admin requests a privileged listener port on the statd command line. So that these requirements are met, nsm_drop_privileges() will now retain CAP_NET_BIND while dropping root. Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Diffstat (limited to 'support')
-rw-r--r--support/nsm/file.c41
1 files changed, 40 insertions, 1 deletions
diff --git a/support/nsm/file.c b/support/nsm/file.c
index 8796705..d469219 100644
--- a/support/nsm/file.c
+++ b/support/nsm/file.c
@@ -67,6 +67,8 @@
#endif
#include <sys/types.h>
+#include <sys/capability.h>
+#include <sys/prctl.h>
#include <sys/stat.h>
#include <ctype.h>
@@ -335,6 +337,34 @@ nsm_is_default_parentdir(void)
return strcmp(nsm_base_dirname, NSM_DEFAULT_STATEDIR) == 0;
}
+/*
+ * Clear all capabilities but CAP_NET_BIND_SERVICE. This permits
+ * callers to acquire privileged source ports, but all other root
+ * capabilities are disallowed.
+ *
+ * Returns true if successful, or false if some error occurred.
+ */
+static _Bool
+nsm_clear_capabilities(void)
+{
+ cap_t caps;
+
+ caps = cap_from_text("cap_net_bind_service=ep");
+ if (caps == NULL) {
+ xlog(L_ERROR, "Failed to allocate capability: %m");
+ return false;
+ }
+
+ if (cap_set_proc(caps) == -1) {
+ xlog(L_ERROR, "Failed to set capability flags: %m");
+ (void)cap_free(caps);
+ return false;
+ }
+
+ (void)cap_free(caps);
+ return true;
+}
+
/**
* nsm_drop_privileges - drop root privileges
* @pidfd: file descriptor of a pid file
@@ -382,6 +412,14 @@ nsm_drop_privileges(const int pidfd)
if (fchown(pidfd, st.st_uid, st.st_gid) == -1)
xlog_warn("Failed to change owner of pidfile: %m");
+ /*
+ * Don't clear capabilities when dropping root.
+ */
+ if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1) {
+ xlog(L_ERROR, "prctl(PR_SET_KEEPCAPS) failed: %m");
+ return 0;
+ }
+
if (setgroups(0, NULL) == -1) {
xlog(L_ERROR, "Failed to drop supplementary groups: %m");
return false;
@@ -399,7 +437,8 @@ nsm_drop_privileges(const int pidfd)
}
xlog(D_CALL, "Effective UID, GID: %u, %u", st.st_uid, st.st_gid);
- return true;
+
+ return nsm_clear_capabilities();
}
/**