You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by mt...@apache.org on 2010/05/28 16:36:08 UTC
svn commit: r949187 - in /trafficserver/traffic/trunk: ./ libinktomi++/
proxy/ proxy/mgmt2/ proxy/mgmt2/utils/
Author: mturk
Date: Fri May 28 14:36:08 2010
New Revision: 949187
URL: http://svn.apache.org/viewvc?rev=949187&view=rev
Log:
TS-338: Alan's patch for enabling posix capabilities
Modified:
trafficserver/traffic/trunk/configure.ac
trafficserver/traffic/trunk/libinktomi++/ink_config.h.in
trafficserver/traffic/trunk/libinktomi++/ink_string.cc
trafficserver/traffic/trunk/proxy/Main.cc
trafficserver/traffic/trunk/proxy/Makefile.am
trafficserver/traffic/trunk/proxy/mgmt2/LocalManager.cc
trafficserver/traffic/trunk/proxy/mgmt2/LocalManager.h
trafficserver/traffic/trunk/proxy/mgmt2/Main.cc
trafficserver/traffic/trunk/proxy/mgmt2/Makefile.am
trafficserver/traffic/trunk/proxy/mgmt2/Rollback.cc
trafficserver/traffic/trunk/proxy/mgmt2/utils/WebMgmtUtils.cc
Modified: trafficserver/traffic/trunk/configure.ac
URL: http://svn.apache.org/viewvc/trafficserver/traffic/trunk/configure.ac?rev=949187&r1=949186&r2=949187&view=diff
==============================================================================
--- trafficserver/traffic/trunk/configure.ac (original)
+++ trafficserver/traffic/trunk/configure.ac Fri May 28 14:36:08 2010
@@ -302,6 +302,17 @@ AC_ARG_ENABLE([eventfd],
AC_MSG_RESULT([$enable_eventfd])
#
+# use POSIX capabilities instead of user ID switching.
+#
+AC_MSG_CHECKING([whether to use POSIX capabilities])
+AC_ARG_ENABLE([posix-cap],
+ [AS_HELP_STRING([--disable-posix-cap],[Use user id switching instead of POSIX capabilities])],
+ [],
+ [enable_posix_cap="yes"]
+)
+AC_MSG_RESULT([$enable_posix_cap])
+
+#
# Installation directories
# For each var the following is evaluated
# foo Standard variable eg. ${prefix}/foo
@@ -789,6 +800,18 @@ AC_MSG_RESULT([$msg])
AC_SUBST(need_union_semun)
+# Check for POSIX capabilities library.
+# If we don't find it, disable checking for header.
+use_posix_cap=0
+AS_IF([test "x$enable_posix_cap" = "xyes"],
+ AC_CHECK_LIB([cap],[cap_set_proc],
+ [AC_SUBST([LIBCAP], ["-lcap"])
+ use_posix_cap=1
+ ],
+ [enable_posix_cap=no]
+ )
+)
+AC_SUBST(use_posix_cap)
# -----------------------------------------------------------------------------
# 5. CHECK FOR HEADER FILES
@@ -894,6 +917,14 @@ ATS_FLAG_HEADERS([google/profiler.h \
], [], [])
fi
+if test "x${enable_posix_cap}" = "xyes"; then
+ AC_CHECK_HEADERS([sys/capability.h],
+ [],
+ [AC_MSG_FAILURE([POSIX capabilities header not found. Try --disable-posix-cap])],
+ []
+ )
+fi
+
ATS_CHECK_DEFAULT_IFACE
ATS_CHECK_GETHOSTBYNAME_R_STYLE
Modified: trafficserver/traffic/trunk/libinktomi++/ink_config.h.in
URL: http://svn.apache.org/viewvc/trafficserver/traffic/trunk/libinktomi%2B%2B/ink_config.h.in?rev=949187&r1=949186&r2=949187&view=diff
==============================================================================
--- trafficserver/traffic/trunk/libinktomi++/ink_config.h.in (original)
+++ trafficserver/traffic/trunk/libinktomi++/ink_config.h.in Fri May 28 14:36:08 2010
@@ -109,6 +109,7 @@
#define ATS_USE_EPOLL @use_epoll@
#define ATS_USE_KQUEUE @use_kqueue@
#define ATS_USE_PORT @use_port@
+#define ATS_USE_POSIX_CAP @use_posix_cap@
/* OS API definitions */
#define GETHOSTBYNAME_R_HOSTENT_DATA @gethostbyname_r_hostent_data@
Modified: trafficserver/traffic/trunk/libinktomi++/ink_string.cc
URL: http://svn.apache.org/viewvc/trafficserver/traffic/trunk/libinktomi%2B%2B/ink_string.cc?rev=949187&r1=949186&r2=949187&view=diff
==============================================================================
--- trafficserver/traffic/trunk/libinktomi++/ink_string.cc (original)
+++ trafficserver/traffic/trunk/libinktomi++/ink_string.cc Fri May 28 14:36:08 2010
@@ -410,19 +410,22 @@ ink_strndup(const char *str, size_t n)
#endif
/*
- * Copyright (c) 1998 Todd C. Miller <To...@courtesan.com>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ strlcat and strlcpy are derived from Todd C. Millers's code.
+
+
+ Copyright (c) 1998 Todd C. Miller <To...@courtesan.com>
+
+ Permission to use, copy, modify, and distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#if !ATS_HAS_STRLCPY
size_t
Modified: trafficserver/traffic/trunk/proxy/Main.cc
URL: http://svn.apache.org/viewvc/trafficserver/traffic/trunk/proxy/Main.cc?rev=949187&r1=949186&r2=949187&view=diff
==============================================================================
--- trafficserver/traffic/trunk/proxy/Main.cc (original)
+++ trafficserver/traffic/trunk/proxy/Main.cc Fri May 28 14:36:08 2010
@@ -47,6 +47,10 @@ extern "C" int plock(int);
#include <mcheck.h>
#endif
+#if ATS_USE_POSIX_CAP
+#include <sys/capability.h>
+#endif
+
#include "Main.h"
#include "signals.h"
#include "Error.h"
@@ -1173,6 +1177,23 @@ init_ink_memalign_heap(void)
}
}
+#if ATS_USE_POSIX_CAP
+// Restore the effective capabilities that we need.
+int
+restoreCapabilities() {
+ int zret = 0; // return value.
+ cap_t cap_set = cap_get_proc(); // current capabilities
+ // Capabilities to restore.
+ cap_value_t cap_list[] = { CAP_NET_ADMIN, CAP_NET_BIND_SERVICE };
+ static int const CAP_COUNT = sizeof(cap_list)/sizeof(*cap_list);
+
+ cap_set_flag(cap_set, CAP_EFFECTIVE, CAP_COUNT, cap_list, CAP_SET);
+ zret = cap_set_proc(cap_set);
+ cap_free(cap_set);
+ return zret;
+}
+#endif
+
static void
adjust_sys_settings(void)
{
@@ -1205,6 +1226,9 @@ adjust_sys_settings(void)
#endif
#endif // linux check
+#if ATS_USE_POSIX_CAP
+ restoreCapabilities();
+#endif
}
struct ShowStats:Continuation
Modified: trafficserver/traffic/trunk/proxy/Makefile.am
URL: http://svn.apache.org/viewvc/trafficserver/traffic/trunk/proxy/Makefile.am?rev=949187&r1=949186&r2=949187&view=diff
==============================================================================
--- trafficserver/traffic/trunk/proxy/Makefile.am (original)
+++ trafficserver/traffic/trunk/proxy/Makefile.am Fri May 28 14:36:08 2010
@@ -174,7 +174,7 @@ traffic_server_LDADD = \
$(top_builddir)/libinktomi++/libinktomi++.a \
@LIBTHREAD@ @LIBSOCKET@ @LIBNSL@ @LIBRESOLV@ @LIBRT@ \
@LIBPCRE@ @LIBDB@ @LIBSQLITE3@ @LIBSSL@ @LIBTCL@ @LIBDL@ \
- @LIBEXPAT@ @LIBDEMANGLE@ @LIBICONV@ \
+ @LIBEXPAT@ @LIBDEMANGLE@ @LIBICONV@ @LIBCAP@ \
@LIBMLD@ @LIBEXC@ @LIBM@ @LIBEV@ @LIBPROFILER@ @LIBEXECINFO@
traffic_logcat_SOURCES = logcat.cc
Modified: trafficserver/traffic/trunk/proxy/mgmt2/LocalManager.cc
URL: http://svn.apache.org/viewvc/trafficserver/traffic/trunk/proxy/mgmt2/LocalManager.cc?rev=949187&r1=949186&r2=949187&view=diff
==============================================================================
--- trafficserver/traffic/trunk/proxy/mgmt2/LocalManager.cc (original)
+++ trafficserver/traffic/trunk/proxy/mgmt2/LocalManager.cc Fri May 28 14:36:08 2010
@@ -40,6 +40,10 @@
#include "WebReconfig.h"
#include "MgmtSocket.h"
+#if ATS_USE_POSIX_CAP
+#include <sys/capability.h>
+#endif
+
int bindProxyPort(int, in_addr_t, int);
bool
@@ -1279,7 +1283,7 @@ LocalManager::listenForProxy()
if (!run_proxy)
return;
- // We we are not already bound, bind the port
+ // We are not already bound, bind the port
for (int i = 0; i < MAX_PROXY_SERVER_PORTS; i++) {
if (proxy_server_port[i] != -1) {
@@ -1307,6 +1311,35 @@ LocalManager::listenForProxy()
return;
} /* End LocalManager::listenForProxy */
+#if ATS_USE_POSIX_CAP
+/** Control file access privileges to bypass DAC.
+ @parm state Use @c true to enable elevated privileges,
+ @c false to disable.
+ @return @c true if successful, @c false otherwise.
+
+ @internal After some pondering I decided that the file access
+ privilege was worth the effort of restricting. Unlike the network
+ privileges this can protect a host system from programming errors
+ by not (usually) permitting such errors to access arbitrary
+ files. This is particularly true since none of the config files
+ current enable this feature so it's not actually called. Still,
+ best to program defensively and have it available.
+ */
+bool
+elevateFileAccess(bool state)
+{
+ bool zret = false; // return value.
+ cap_t cap_state = cap_get_proc(); // current capabilities
+ // Make a list of the capabilities we changed.
+ cap_value_t cap_list[] = { CAP_DAC_OVERRIDE };
+ static int const CAP_COUNT = sizeof(cap_list)/sizeof(*cap_list);
+
+ cap_set_flag(cap_state, CAP_EFFECTIVE, CAP_COUNT, cap_list, state ? CAP_SET : CAP_CLEAR);
+ zret = (0 == cap_set_proc(cap_state));
+ cap_free(cap_state);
+ return zret;
+}
+#else
// bool removeRootPriv()
//
// - Returns true on success
@@ -1316,16 +1349,14 @@ bool
removeRootPriv(uid_t euid)
{
if (seteuid(euid) < 0) {
- Debug("lm", "[restoreRootPriv] seteuid failed : %s\n", strerror(errno));
+ Debug("lm", "[removeRootPriv] seteuid failed : %s\n", strerror(errno));
return false;
}
Debug("lm", "[removeRootPriv] removed root privileges. Euid is %d\n", euid);
-
return true;
}
-
// bool restoreRootPriv()
//
// - Returns true on success
@@ -1345,6 +1376,7 @@ restoreRootPriv(uid_t *old_euid)
return true;
}
+#endif
/*
* bindProxyPort()
@@ -1357,6 +1389,8 @@ bindProxyPort(int proxy_port, in_addr_t
int one = 1;
struct sockaddr_in proxy_addr;
int proxy_port_fd = -1;
+
+#if !ATS_USE_POSIX_CAP
bool privBoost = false;
uid_t euid = geteuid();
uid_t saved_euid = 0;
@@ -1370,6 +1404,7 @@ bindProxyPort(int proxy_port, in_addr_t
privBoost = true;
}
}
+#endif
/* Setup reliable connection, for large config changes */
if ((proxy_port_fd = socket(AF_INET, type, 0)) < 0) {
@@ -1393,12 +1428,16 @@ bindProxyPort(int proxy_port, in_addr_t
Debug("lm", "[bindProxyPort] Successfully bound proxy port %d\n", proxy_port);
- if (privBoost == true) {
- if (removeRootPriv(saved_euid) == false) {
- mgmt_elog(stderr, "[bindProxyPort] Unable to reset permissions to euid %d. Exiting...\n", getuid());
- _exit(1);
+#if !ATS_USE_POSIX_CAP
+ if (proxy_port < 1024 && euid != 0) {
+ if (privBoost == true) {
+ if (removeRootPriv(saved_euid) == false) {
+ mgmt_elog(stderr, "[bindProxyPort] Unable to reset permissions to euid %d. Exiting...\n", getuid());
+ _exit(1);
+ }
}
}
+#endif
return proxy_port_fd;
} /* End bindProxyPort */
Modified: trafficserver/traffic/trunk/proxy/mgmt2/LocalManager.h
URL: http://svn.apache.org/viewvc/trafficserver/traffic/trunk/proxy/mgmt2/LocalManager.h?rev=949187&r1=949186&r2=949187&view=diff
==============================================================================
--- trafficserver/traffic/trunk/proxy/mgmt2/LocalManager.h (original)
+++ trafficserver/traffic/trunk/proxy/mgmt2/LocalManager.h Fri May 28 14:36:08 2010
@@ -193,8 +193,11 @@ private:
}; /* End class LocalManager */
+#if ATS_USE_POSIX_CAP
+bool elevateFileAccess(bool);
+#else
bool restoreRootPriv(uid_t *old_euid = NULL);
bool removeRootPriv(uid_t euid);
-
+#endif
#endif /* _LOCAL_MANAGER_H */
Modified: trafficserver/traffic/trunk/proxy/mgmt2/Main.cc
URL: http://svn.apache.org/viewvc/trafficserver/traffic/trunk/proxy/mgmt2/Main.cc?rev=949187&r1=949186&r2=949187&view=diff
==============================================================================
--- trafficserver/traffic/trunk/proxy/mgmt2/Main.cc (original)
+++ trafficserver/traffic/trunk/proxy/mgmt2/Main.cc Fri May 28 14:36:08 2010
@@ -73,7 +73,9 @@
#include "P_RecLocal.h"
#include "P_RecCore.h"
-
+#if ATS_USE_POSIX_CAP
+#include <sys/capability.h>
+#endif
#define FD_THROTTLE_HEADROOM (128 + 64) // TODO: consolidate with THROTTLE_FD_HEADROOM
@@ -1400,6 +1402,39 @@ fileUpdated(char *fname)
return;
} /* End fileUpdate */
+#if ATS_USE_POSIX_CAP
+/** Restore capabilities after user id change.
+ This manipulates LINUX capabilities so that this process
+ can perform certain privileged operations even if it is
+ no longer running as a privilege user.
+
+ @internal
+ I tried using
+ @code
+ prctl(PR_SET_KEEPCAPS, 1);
+ @endcode
+ but that had no effect even though the call reported succes.
+ Only explicit capability manipulation was effective.
+
+ It does not appear to be necessary to set the capabilities on the
+ executable if originally run as root. That may be needed if
+ started as a user without that capability.
+ */
+
+int
+restoreCapabilities() {
+ int zret = 0; // return value.
+ cap_t cap_set = cap_get_proc(); // current capabilities
+ // Make a list of the capabilities we want turned on.
+ cap_value_t cap_list[] = { CAP_NET_ADMIN, CAP_NET_BIND_SERVICE };
+ static int const CAP_COUNT = sizeof(cap_list)/sizeof(*cap_list);
+
+ cap_set_flag(cap_set, CAP_EFFECTIVE, CAP_COUNT, cap_list, CAP_SET);
+ zret = cap_set_proc(cap_set);
+ cap_free(cap_set);
+ return zret;
+}
+#endif
// void runAsUser(...)
//
@@ -1430,6 +1465,7 @@ runAsUser(char *userName)
mgmt_elog(stderr, "[runAsUser] Fatal Error: proxy.config.admin.user_id is not set\n", userName, strerror(errno));
_exit(1);
}
+
// this is behaving weird. refer to getpwnam(3C) sparc -jcoates
// this looks like the POSIX getpwnam_r
@@ -1471,6 +1507,13 @@ runAsUser(char *userName)
mgmt_elog(stderr, "[runAsUser] Fatal Error: Failed to switch to user %s\n", userName);
_exit(1);
}
+
+#if ATS_USE_POSIX_CAP
+ if (restoreCapabilities()) {
+ mgmt_elog(stderr, "[runAsUser] Error: Failed to restore capabilities after switch to user %s.\n", userName);
+ }
+#endif
+
}
} /* End runAsUser() */
Modified: trafficserver/traffic/trunk/proxy/mgmt2/Makefile.am
URL: http://svn.apache.org/viewvc/trafficserver/traffic/trunk/proxy/mgmt2/Makefile.am?rev=949187&r1=949186&r2=949187&view=diff
==============================================================================
--- trafficserver/traffic/trunk/proxy/mgmt2/Makefile.am (original)
+++ trafficserver/traffic/trunk/proxy/mgmt2/Makefile.am Fri May 28 14:36:08 2010
@@ -117,4 +117,4 @@ traffic_manager_LDADD = \
@LIBEXPAT@ @LIBPCRE@ \
@LIBSSL@ @LIBDB@ @LIBSQLITE3@ @LIBTCL@ @LIBICONV@ \
@LIBM@ @LIBDL@ @LIBSOCKET@ @LIBNSL@ @LIBRESOLV@ \
- @LIBTHREAD@ @LIBRT@ @LIBEXECINFO@
+ @LIBTHREAD@ @LIBRT@ @LIBEXECINFO@ @LIBCAP@
Modified: trafficserver/traffic/trunk/proxy/mgmt2/Rollback.cc
URL: http://svn.apache.org/viewvc/trafficserver/traffic/trunk/proxy/mgmt2/Rollback.cc?rev=949187&r1=949186&r2=949187&view=diff
==============================================================================
--- trafficserver/traffic/trunk/proxy/mgmt2/Rollback.cc (original)
+++ trafficserver/traffic/trunk/proxy/mgmt2/Rollback.cc Fri May 28 14:36:08 2010
@@ -286,20 +286,37 @@ Rollback::statFile(version_t version, st
{
char *filePath;
int statResult;
+#if !ATS_USE_POSIX_CAP
uid_t saved_euid = 0;
+#endif
if (version == this->currentVersion) {
version = ACTIVE_VERSION;
}
filePath = createPathStr(version);
+
if (root_access_needed) {
- if (restoreRootPriv(&saved_euid) != true) {
+ if (
+#if ATS_USE_POSIX_CAP
+ elevateFileAccess(true)
+#else
+ restoreRootPriv(&saved_euid)
+#endif
+ != true) {
mgmt_log(stderr, "[Rollback] Unable to acquire root privileges.\n");
}
}
+
statResult = stat(filePath, buf);
+
if (root_access_needed) {
- if (removeRootPriv(saved_euid) != true) {
+ if (
+#if ATS_USE_POSIX_CAP
+ elevateFileAccess(false)
+#else
+ removeRootPriv(saved_euid)
+#endif
+ != true) {
mgmt_log(stderr, "[Rollback] Unable to restore non-root privileges.\n");
}
}
@@ -318,21 +335,37 @@ Rollback::openFile(version_t version, in
{
char *filePath;
int fd;
+#if !ATS_USE_POSIX_CAP
uid_t saved_euid = 0;
+#endif
filePath = createPathStr(version);
if (root_access_needed) {
- if (restoreRootPriv(&saved_euid) != true) {
+ if (
+#if ATS_USE_POSIX_CAP
+ elevateFileAccess(true)
+#else
+ restoreRootPriv(&saved_euid)
+#endif
+ != true) {
mgmt_log(stderr, "[Rollback] Unable to acquire root privileges.\n");
}
}
+
fd = mgmt_open_mode(filePath, oflags, 0644);
if (root_access_needed) {
- if (removeRootPriv(saved_euid) != true) {
+ if (
+#if ATS_USE_POSIX_CAP
+ elevateFileAccess(false)
+#else
+ removeRootPriv(saved_euid)
+#endif
+ != true) {
mgmt_log(stderr, "[Rollback] Unable to restore non-root privileges.\n");
}
}
+
if (fd < 0) {
if (errnoPtr != NULL) {
*errnoPtr = errno;
Modified: trafficserver/traffic/trunk/proxy/mgmt2/utils/WebMgmtUtils.cc
URL: http://svn.apache.org/viewvc/trafficserver/traffic/trunk/proxy/mgmt2/utils/WebMgmtUtils.cc?rev=949187&r1=949186&r2=949187&view=diff
==============================================================================
--- trafficserver/traffic/trunk/proxy/mgmt2/utils/WebMgmtUtils.cc (original)
+++ trafficserver/traffic/trunk/proxy/mgmt2/utils/WebMgmtUtils.cc Fri May 28 14:36:08 2010
@@ -1518,7 +1518,9 @@ processSpawn(const char *args[],
long total;
bool cutoff;
const char *too_large_msg = "\nfile too large, truncated here...";
+#if !ATS_USE_POSIX_CAP
uid_t saved_euid = 0;
+#endif
if (pipe(stdinPipe) == -1)
mgmt_elog(stderr, "[processSpawn] unable to create stdin pipe\n");
@@ -1538,6 +1540,27 @@ processSpawn(const char *args[],
for (int i = 0; i < MAX_PROXY_SERVER_PORTS && lmgmt->proxy_server_fd[i] >= 0; i++) {
close_socket(lmgmt->proxy_server_fd[i]);
}
+#if ATS_USE_POSIX_CAP
+ /* There is no point in saving the current euid in order to
+ restore it because at this point the process will either exec
+ or exit. The thread of execution will neither linger nor return
+ here.
+
+ I don't understand what the point in the original code was of
+ setuid(geteuid()) after reverting to root euid. If the latter
+ works, you don't need the former, and if the latter doesn't
+ work, the former won't work either. Is it some sort of error
+ checking? But why not just check the return value of
+ restoreRootPriv?
+
+ AFAICT this code is used only by the web interface which is
+ currently non-functional. If that interface is recovered it
+ would be worthwhile to look at why, exactly, it needs to have
+ processes run as root.
+ */
+ if (-1 == seteuid(0))
+ mgmt_elog(stderr, "[processSpawn] unable to set effective user id to 0");
+#else
// set uid to be the effective uid if it's run as root
if (run_as_root) {
restoreRootPriv(&saved_euid);
@@ -1545,6 +1568,7 @@ processSpawn(const char *args[],
mgmt_elog(stderr, "[processSpawn] unable to set uid to euid");
}
}
+#endif
if (nowait) {
// nowait - detach from parent process
if (setsid() == (pid_t) - 1) {
@@ -1630,9 +1654,11 @@ processSpawn(const char *args[],
}
}
+#if !ATS_USE_POSIX_CAP
if (run_as_root) {
removeRootPriv(saved_euid);
}
+#endif
#endif // _WIN32
return status;
}