Index: configure.ac =================================================================== --- configure.ac (revision 42015) +++ configure.ac (working copy) @@ -307,6 +307,10 @@ AST_EXT_LIB_CHECK([CURSES], [curses], [initscr], [curses.h]) +if test "x${host_os}" = "xlinux-gnu" ; then + AST_EXT_LIB([cap], [cap_from_text], [sys/capability.h], [POSIX1E], [Linux POSIX.1e Capabilities]) +fi + GSM_INTERNAL="yes" AC_SUBST(GSM_INTERNAL) GSM_SYSTEM="yes" Index: doc/security.txt =================================================================== --- doc/security.txt (revision 42015) +++ doc/security.txt (working copy) @@ -28,6 +28,13 @@ 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: Index: main/Makefile =================================================================== --- main/Makefile (revision 42015) +++ main/Makefile (working copy) @@ -48,6 +48,9 @@ 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 Index: main/asterisk.c =================================================================== --- main/asterisk.c (revision 42015) +++ main/asterisk.c (working copy) @@ -80,13 +80,12 @@ #include #ifdef linux #include -#endif +#ifdef HAVE_POSIX1E +#include +#endif /* HAVE_POSIX1E */ +#endif /* linux */ #include -#ifdef linux -#include -#endif - #if defined(__FreeBSD__) || defined( __NetBSD__ ) || defined(SOLARIS) #include #if defined(SOLARIS) @@ -2489,12 +2488,22 @@ } if (!is_child_of_nonroot && runuser) { +#if (defined(linux) && defined(HAVE_POSIX1E)) + cap_t cap; + int has_cap = 1; +#endif /* HAVE_POSIX1E */ struct passwd *pw; pw = getpwnam(runuser); if (!pw) { ast_log(LOG_WARNING, "No such user '%s'!\n", runuser); exit(1); } +#if (defined(linux) && defined(HAVE_POSIX1E)) + if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) { + ast_log(LOG_WARNING, "Unable to keep capabilities.\n"); + has_cap = 0; + } +#endif /* HAVE_POSIX1E */ if (!rungroup) { if (setgid(pw->pw_gid)) { ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid); @@ -2512,6 +2521,20 @@ setenv("ASTERISK_ALREADY_NONROOT", "yes", 1); if (option_verbose) ast_verbose("Running as user '%s'\n", runuser); +#if (defined(linux) && defined(HAVE_POSIX1E)) + do { + if (has_cap) { + cap = cap_from_text("cap_net_admin=ep"); + if (cap_set_proc(cap)) { + ast_log(LOG_WARNING, "Unable to install capabilities.\n"); + break; + } + if (cap_free(cap)) { + ast_log(LOG_WARNING, "Unable to drop capabilities.\n"); + } + } + } while (0); +#endif /* HAVE_POSIX1E */ } #endif /* __CYGWIN__ */ Index: makeopts.in =================================================================== --- makeopts.in (revision 42015) +++ makeopts.in (working copy) @@ -156,3 +156,6 @@ SUPPSERV_INCLUDE=@SUPPSERV_INCLUDE@ SUPPSERV_LIB=@SUPPSERV_LIB@ + +CAP_LIB=@POSIX1E_LIB@ +CAP_INCLUDE=@POSIX1E_INCLUDE@