3535#include <sys/stat.h>
3636#include <sys/time.h>
3737#include <sys/resource.h>
38+ #ifdef HAVE_LIBCAP
39+ #include <sys/prctl.h>
40+ #include <sys/capability.h>
41+ #endif
3842#include <signal.h>
3943#include <errno.h>
4044#include <ev.h>
@@ -222,6 +226,30 @@ drop_perms(const char *username) {
222226 else if (user == NULL )
223227 fatal ("getpwnam(): user %s does not exist" , username );
224228
229+ #ifdef HAVE_LIBCAP
230+ cap_t caps ;
231+ cap_value_t cap_list [1 ];
232+
233+ /* add permitted flag to capability needed for IP_TRANSPARENT */
234+ if (CAP_IS_SUPPORTED (CAP_NET_RAW )) {
235+ caps = cap_get_proc ();
236+ if (caps == NULL )
237+ fatal ("cap_get_proc(): %s" , strerror (errno ));
238+
239+ cap_list [0 ] = CAP_NET_RAW ;
240+ if (cap_set_flag (caps , CAP_PERMITTED , 1 , cap_list , CAP_SET ) == -1 )
241+ fatal ("cap_set_flags(): %s" , strerror (errno ));
242+
243+ if (cap_set_proc (caps ) == -1 )
244+ fatal ("cap_set_proc(): %s" , strerror (errno ));
245+
246+ cap_free (caps );
247+
248+ /* keep capabilities after setuid */
249+ prctl (PR_SET_KEEPCAPS , 1 , 0 , 0 , 0 );
250+ }
251+ #endif
252+
225253 /* drop any supplementary groups */
226254 if (setgroups (1 , & user -> pw_gid ) < 0 )
227255 fatal ("setgroups(): %s" , strerror (errno ));
@@ -231,6 +259,35 @@ drop_perms(const char *username) {
231259
232260 if (setuid (user -> pw_uid ) < 0 )
233261 fatal ("setuid(): %s" , strerror (errno ));
262+
263+ #ifdef HAVE_LIBCAP
264+ /* enable capability needed for IP_TRANSPARENT */
265+ if (CAP_IS_SUPPORTED (CAP_NET_RAW )) {
266+ caps = cap_get_proc ();
267+ if (caps == NULL )
268+ fatal ("cap_get_proc(): %s" , strerror (errno ));
269+
270+ /* remove every capability from the list */
271+ cap_clear (caps );
272+ cap_list [0 ] = CAP_NET_RAW ;
273+ /* take back capability */
274+ if (cap_set_flag (caps , CAP_PERMITTED , 1 , cap_list , CAP_SET ) == -1 )
275+ fatal ("cap_set_flags(): %s" , strerror (errno ));
276+ /* take back capability */
277+ if (cap_set_flag (caps , CAP_EFFECTIVE , 1 , cap_list , CAP_SET ) == -1 )
278+ fatal ("cap_set_flags(): %s" , strerror (errno ));
279+
280+ if (cap_set_proc (caps ) == -1 )
281+ fatal ("back cap_set_proc(): %s" , strerror (errno ));
282+ /* from now on it the new capability list is active,
283+ * no other capabilities may be enabled */
284+
285+ cap_free (caps );
286+
287+ /* disable keeping capabilities across setuid */
288+ prctl (PR_SET_KEEPCAPS , 0 , 0 , 0 , 0 );
289+ }
290+ #endif
234291}
235292
236293static void
0 commit comments