Backport libcap patch from trunk

When asterisk runs as a plain user, it can't set the Type of Service (ToS)
field of IP to mark the packets as realtime traffic.

This patch allows Asterisk to keep the CAP_NET_ADMIN capability when dropping
privileges.

---
 configure.ac                     |    5 +++++
 doc/security.txt                 |    7 +++++++
 include/asterisk/autoconfig.h.in |    6 ++++++
 main/Makefile                    |    3 +++
 main/asterisk.c                  |   31 ++++++++++++++++++++++++++-----
 makeopts.in                      |    3 +++
 6 files changed, 50 insertions(+), 5 deletions(-)

--- a/configure.ac
+++ b/configure.ac
@@ -174,6 +174,7 @@ AC_SUBST(AST_DEVMODE)
 
 AST_EXT_LIB_SETUP([ALSA], [Advanced Linux Sound Architecture], [asound])
 AST_EXT_LIB_SETUP([CURL], [cURL], [curl])
+AST_EXT_LIB_SETUP([CAP], [POSIX 1.e capabilities], [cap])
 AST_EXT_LIB_SETUP([CURSES], [curses], [curses])
 AST_EXT_LIB_SETUP([GNUTLS], [GNU TLS support (used for iksemel only)], [gnutls])
 AST_EXT_LIB_SETUP([GSM], [GSM], [gsm], [, or 'internal'])
@@ -399,6 +400,10 @@ AST_EXT_LIB_CHECK([ALSA], [asound], [snd
 
 AST_EXT_LIB_CHECK([CURSES], [curses], [initscr], [curses.h])
 
+if test "x${host_os}" = "xlinux-gnu" ; then
+  AST_EXT_LIB_CHECK([CAP], [cap], [cap_from_text], [sys/capability.h])
+fi
+
 GSM_INTERNAL="yes"
 AC_SUBST(GSM_INTERNAL)
 GSM_SYSTEM="yes"
--- a/doc/security.txt
+++ b/doc/security.txt
@@ -28,6 +28,13 @@ The IAX2 protocol supports strong RSA ke
 AES encryption of voice and signalling. The SIP channel does not
 support encryption in this version of Asterisk.
 
+By default, if you have libcap available, Asterisk will try to retain the
+CAP_NET_ADMIN capability when running as a non-root user. If you do not need
+that capability you may want to configure Asterisk with --without-cap; however,
+this will prevent Asterisk from being able to mark high ToS bits under Linux.
+More information on CAP_NET_ADMIN is available at:
+http://www.lids.org/lids-howto/node48.html
+
 * DIALPLAN SECURITY
 
 First and foremost remember this:
--- a/main/asterisk.c
+++ b/main/asterisk.c
@@ -82,13 +82,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revisi
 #include <sys/stat.h>
 #ifdef linux
 #include <sys/prctl.h>
-#endif
+#ifdef HAVE_CAP
+#include <sys/capability.h>
+#endif /* HAVE_CAP */
+#endif /* linux */
 #include <regex.h>
 
-#ifdef linux
-#include <sys/prctl.h>
-#endif
-
 #if  defined(__FreeBSD__) || defined( __NetBSD__ ) || defined(SOLARIS)
 #include <netdb.h>
 #if defined(SOLARIS)
@@ -2734,12 +2733,21 @@ int main(int argc, char *argv[])
 	}
 
 	if (runuser && !ast_test_flag(&ast_options, AST_OPT_FLAG_REMOTE)) {
+#ifdef HAVE_CAP
+		int has_cap = 1;
+#endif /* HAVE_CAP */
 		struct passwd *pw;
 		pw = getpwnam(runuser);
 		if (!pw) {
 			ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
 			exit(1);
 		}
+#ifdef HAVE_CAP
+		if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
+			ast_log(LOG_WARNING, "Unable to keep capabilities.\n");
+			has_cap = 0;
+		}
+#endif /* HAVE_CAP */
 		if (!isroot && pw->pw_uid != geteuid()) {
 			ast_log(LOG_ERROR, "Asterisk started as nonroot, but runuser '%s' requested.\n", runuser);
 			exit(1);
@@ -2760,6 +2768,19 @@ int main(int argc, char *argv[])
 		}
 		if (option_verbose)
 			ast_verbose("Running as user '%s'\n", runuser);
+#ifdef HAVE_CAP
+		if (has_cap) {
+			cap_t cap;
+
+			cap = cap_from_text("cap_net_admin=ep");
+
+			if (cap_set_proc(cap))
+				ast_log(LOG_WARNING, "Unable to install capabilities.\n");
+
+			if (cap_free(cap))
+				ast_log(LOG_WARNING, "Unable to drop capabilities.\n");
+		}
+#endif /* HAVE_CAP */
 	}
 
 #endif /* __CYGWIN__ */
--- a/main/Makefile
+++ b/main/Makefile
@@ -55,6 +55,9 @@ ifneq ($(findstring $(OSARCH), linux-gnu
   ifneq ($(findstring LOADABLE_MODULES,$(MENUSELECT_CFLAGS)),)
   AST_LIBS+=-ldl
   endif
+  ifneq (x$(CAP_LIB),x)
+    AST_LIBS+=$(CAP_LIB)
+  endif
   AST_LIBS+=-lpthread $(EDITLINE_LIB) -lm -lresolv
 else
   AST_LIBS+=$(EDITLINE_LIB) -lm
--- a/makeopts.in
+++ b/makeopts.in
@@ -179,6 +179,9 @@ MISDN_LIB=@MISDN_LIB@
 SUPPSERV_INCLUDE=@SUPPSERV_INCLUDE@
 SUPPSERV_LIB=@SUPPSERV_LIB@
 
+CAP_LIB=@CAP_LIB@
+CAP_INCLUDE=@CAP_INCLUDE@
+
 TERMCAP_INCLUDE=@TERMCAP_INCLUDE@
 TERMCAP_LIB=@TERMCAP_LIB@
 TERMCAP_DIR=@TERMCAP_DIR@
--- a/include/asterisk/autoconfig.h.in
+++ b/include/asterisk/autoconfig.h.in
@@ -62,6 +62,12 @@
 /* Define to 1 if you have the `bzero' function. */
 #undef HAVE_BZERO
 
+/* Define this to indicate the ${CAP_DESCRIP} library */
+#undef HAVE_CAP
+
+/* Define to indicate the ${CAP_DESCRIP} library version */
+#undef HAVE_CAP_VERSION
+
 /* Define to 1 if your system has a working `chown' function. */
 #undef HAVE_CHOWN
 
