From 070ed778b8ea7cc13f1407d0d66fefc51c910ac2 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 3 May 2010 19:14:55 +0200 Subject: [PATCH] Libcap-ng support by Gurvinder Singh and myself. Basic support for per thread caps is added, but not activated as it doesn't seem to work yet. Work around for incompatibility between libnet 1.1 and libcap-ng added. --- config.h.in | 3 + configure.in | 36 ++++++ src/Makefile.am | 1 + src/alert-debuglog.c | 2 + src/alert-fastlog.c | 2 + src/alert-prelude.c | 2 + src/alert-unified-alert.c | 2 + src/alert-unified-log.c | 2 + src/alert-unified2-alert.c | 2 + src/counters.c | 13 ++- src/detect-parse.c | 46 +++++--- src/detect.c | 2 + src/flow.c | 5 + src/log-httplog.c | 2 + src/respond-reject-libnet11.c | 4 + src/respond-reject.c | 2 + src/runmodes.c | 1 + src/source-ipfw.c | 6 + src/source-nfq.c | 4 + src/source-pcap-file.c | 3 + src/source-pcap.c | 3 + src/source-pfring.c | 4 + src/stream-tcp.c | 2 + src/suricata.c | 60 +++++++++- src/threadvars.h | 2 + src/tm-modules.h | 3 + src/tm-threads.c | 18 +++ src/util-error.c | 5 + src/util-error.h | 5 + src/util-privs.c | 205 ++++++++++++++++++++++++++++++++++ src/util-privs.h | 82 ++++++++++++++ 31 files changed, 512 insertions(+), 17 deletions(-) create mode 100644 src/util-privs.c create mode 100644 src/util-privs.h diff --git a/config.h.in b/config.h.in index 2344e27f65..b74615d42b 100644 --- a/config.h.in +++ b/config.h.in @@ -12,6 +12,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H +/* Define to 1 if you have the `cap-ng' library (-lcap-ng). */ +#undef HAVE_LIBCAP_NG + /* Define to 1 if you have the `cuda' library (-lcuda). */ #undef HAVE_LIBCUDA diff --git a/configure.in b/configure.in index c8509eea2c..eab96b4527 100644 --- a/configure.in +++ b/configure.in @@ -698,6 +698,42 @@ AC_CHECK_HEADER(pcap.h,,[AC_ERROR(pcap.h not found ...)]) fi fi +# Check for libcap-ng + + AC_ARG_WITH(libcap_ng_includes, + [ --with-libcap_ng-includes=DIR libcap_ng include directory], + [with_libcap-ng_includes="$withval"],[with_libcap_ng_includes=no]) + AC_ARG_WITH(libcap_ng_libraries, + [ --with-libcap_ng-libraries=DIR libcap_ng library directory], + [with_libcap_ng_libraries="$withval"],[with_libcap_ng_libraries="no"]) + + if test "$with_libcap_ng_includes" != "no"; then + CPPFLAGS="${CPPFLAGS} -I${with_libcap_ng_includes}" + fi + + if test "$with_libcap_ng_libraries" != "no"; then + LDFLAGS="${LDFLAGS} -L${with_libcap_ng_libraries}" + fi + + AC_CHECK_HEADER(cap-ng.h,,LIBCAP_NG="no") + if test "$LIBCAP_NG" != "no"; then + LIBCAP_NG="" + AC_CHECK_LIB(cap-ng,capng_clear,,LIBCAP_NG="no") + fi + + if test "$LIBCAP_NG" != "no"; then + CFLAGS="${CFLAGS} -DHAVE_LIBCAP_NG" + fi + + if test "$LIBCAP_NG" = "no"; then + echo + echo " WARNING! libcap-ng library not found, go get it" + echo " from http://people.redhat.com/sgrubb/libcap-ng/" + echo " or check your package manager." + echo + echo " Suricata will be built without support for dropping privs." + echo + fi AC_SUBST(CFLAGS) AC_SUBST(LDFLAGS) diff --git a/src/Makefile.am b/src/Makefile.am index ae94196342..9e6eaa32c1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -155,6 +155,7 @@ util-strlcatu.c \ util-strlcpyu.c \ util-cuda.c util-cuda.h \ util-cuda-handlers.c util-cuda-handlers.h \ +util-privs.c util-privs.h \ tm-modules.c tm-modules.h \ tm-queues.c tm-queues.h \ tm-queuehandlers.c tm-queuehandlers.h \ diff --git a/src/alert-debuglog.c b/src/alert-debuglog.c index b05930677c..09ace7ec5d 100644 --- a/src/alert-debuglog.c +++ b/src/alert-debuglog.c @@ -28,6 +28,7 @@ #include "output.h" #include "alert-debuglog.h" +#include "util-privs.h" #define DEFAULT_LOG_FILENAME "alert-debug.log" @@ -48,6 +49,7 @@ void TmModuleAlertDebugLogRegister (void) { tmm_modules[TMM_ALERTDEBUGLOG].ThreadExitPrintStats = AlertDebugLogExitPrintStats; tmm_modules[TMM_ALERTDEBUGLOG].ThreadDeinit = AlertDebugLogThreadDeinit; tmm_modules[TMM_ALERTDEBUGLOG].RegisterTests = NULL; + tmm_modules[TMM_ALERTDEBUGLOG].cap_flags = 0; OutputRegisterModule(MODULE_NAME, "alert-debug", AlertDebugLogInitCtx); } diff --git a/src/alert-fastlog.c b/src/alert-fastlog.c index f710327384..10c32cc014 100644 --- a/src/alert-fastlog.c +++ b/src/alert-fastlog.c @@ -37,6 +37,7 @@ #include "util-mpm-b2g-cuda.h" #include "util-cuda-handlers.h" +#include "util-privs.h" #define DEFAULT_LOG_FILENAME "fast.log" @@ -59,6 +60,7 @@ void TmModuleAlertFastLogRegister (void) { tmm_modules[TMM_ALERTFASTLOG].ThreadExitPrintStats = AlertFastLogExitPrintStats; tmm_modules[TMM_ALERTFASTLOG].ThreadDeinit = AlertFastLogThreadDeinit; tmm_modules[TMM_ALERTFASTLOG].RegisterTests = AlertFastLogRegisterTests; + tmm_modules[TMM_ALERTFASTLOG].cap_flags = 0; OutputRegisterModule(MODULE_NAME, "fast", AlertFastLogInitCtx); } diff --git a/src/alert-prelude.c b/src/alert-prelude.c index f414d82e6e..054543e0fd 100644 --- a/src/alert-prelude.c +++ b/src/alert-prelude.c @@ -38,6 +38,7 @@ #include "util-error.h" #include "output.h" +#include "util-privs.h" #ifndef PRELUDE /** Handle the case where no PRELUDE support is compiled in. @@ -117,6 +118,7 @@ void TmModuleAlertPreludeRegister (void) { tmm_modules[TMM_ALERTPRELUDE].Func = AlertPrelude; tmm_modules[TMM_ALERTPRELUDE].ThreadDeinit = AlertPreludeThreadDeinit; tmm_modules[TMM_ALERTPRELUDE].RegisterTests = AlertPreludeRegisterTests; + tmm_modules[TMM_ALERTPRELUDE].cap_flags = 0; OutputRegisterModule("AlertPrelude", "alert-prelude", AlertPreludeInitCtx); } diff --git a/src/alert-unified-alert.c b/src/alert-unified-alert.c index 80303870bd..22f20c5b30 100644 --- a/src/alert-unified-alert.c +++ b/src/alert-unified-alert.c @@ -29,6 +29,7 @@ #include "output.h" #include "alert-unified-alert.h" +#include "util-privs.h" #define DEFAULT_LOG_FILENAME "unified.alert" @@ -53,6 +54,7 @@ void TmModuleAlertUnifiedAlertRegister (void) { tmm_modules[TMM_ALERTUNIFIEDALERT].Func = AlertUnifiedAlert; tmm_modules[TMM_ALERTUNIFIEDALERT].ThreadDeinit = AlertUnifiedAlertThreadDeinit; tmm_modules[TMM_ALERTUNIFIEDALERT].RegisterTests = AlertUnifiedAlertRegisterTests; + tmm_modules[TMM_ALERTUNIFIEDALERT].cap_flags = 0; OutputRegisterModule(MODULE_NAME, "unified-alert", AlertUnifiedAlertInitCtx); } diff --git a/src/alert-unified-log.c b/src/alert-unified-log.c index 3d2d6c8599..de4fd0d75f 100644 --- a/src/alert-unified-log.c +++ b/src/alert-unified-log.c @@ -30,6 +30,7 @@ #include "output.h" #include "alert-unified-log.h" +#include "util-privs.h" #define DEFAULT_LOG_FILENAME "unified.log" @@ -54,6 +55,7 @@ void TmModuleAlertUnifiedLogRegister (void) { tmm_modules[TMM_ALERTUNIFIEDLOG].Func = AlertUnifiedLog; tmm_modules[TMM_ALERTUNIFIEDLOG].ThreadDeinit = AlertUnifiedLogThreadDeinit; tmm_modules[TMM_ALERTUNIFIEDLOG].RegisterTests = AlertUnifiedLogRegisterTests; + tmm_modules[TMM_ALERTUNIFIEDLOG].cap_flags = 0; OutputRegisterModule(MODULE_NAME, "unified-log", AlertUnifiedLogInitCtx); diff --git a/src/alert-unified2-alert.c b/src/alert-unified2-alert.c index a88c732913..3e5516a57d 100644 --- a/src/alert-unified2-alert.c +++ b/src/alert-unified2-alert.c @@ -25,6 +25,7 @@ #include "output.h" #include "alert-unified2-alert.h" +#include "util-privs.h" #ifndef IPPROTO_SCTP #define IPPROTO_SCTP 132 @@ -138,6 +139,7 @@ void TmModuleUnified2AlertRegister (void) { tmm_modules[TMM_ALERTUNIFIED2ALERT].Func = Unified2Alert; tmm_modules[TMM_ALERTUNIFIED2ALERT].ThreadDeinit = Unified2AlertThreadDeinit; tmm_modules[TMM_ALERTUNIFIED2ALERT].RegisterTests = Unified2RegisterTests; + tmm_modules[TMM_ALERTUNIFIED2ALERT].cap_flags = 0; OutputRegisterModule(MODULE_NAME, "unified2-alert", Unified2AlertInitCtx); } diff --git a/src/counters.c b/src/counters.c index 8dccdf4039..934c7331b8 100644 --- a/src/counters.c +++ b/src/counters.c @@ -12,6 +12,7 @@ #include "util-time.h" #include "util-unittest.h" #include "util-debug.h" +#include "util-privs.h" /** \todo Get the default log directory from some global resource. */ #define SC_PERF_DEFAULT_LOG_FILENAME "stats.log" @@ -356,6 +357,11 @@ static void *SCPerfMgmtThread(void *arg) /* Set the thread name */ SCSetThreadName(tv_local->name); + /* Set the threads capability */ + tv_local->cap_flags = 0; + + SCDropCaps(tv_local); + if (sc_perf_op_ctx == NULL) { SCLogError(SC_ERR_PERF_STATS_NOT_INIT, "Perf Counter API not init" "SCPerfInitCounterApi() has to be called first"); @@ -403,6 +409,11 @@ static void *SCPerfWakeupThread(void *arg) /* Set the thread name */ SCSetThreadName(tv_local->name); + /* Set the threads capability */ + tv_local->cap_flags = 0; + + SCDropCaps(tv_local); + if (sc_perf_op_ctx == NULL) { SCLogError(SC_ERR_PERF_STATS_NOT_INIT, "Perf Counter API not init" "SCPerfInitCounterApi() has to be called first"); @@ -1657,10 +1668,8 @@ void SCPerfReleasePCA(SCPerfCounterArray *pca) return; } - /*----------------------------------Unit_Tests--------------------------------*/ - static int SCPerfTestCounterReg01() { SCPerfContext pctx; diff --git a/src/detect-parse.c b/src/detect-parse.c index cb03b60581..9079b7a2b2 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -30,6 +30,8 @@ #include "detect-parse.h" #include "detect-engine-iponly.h" +extern int sc_set_caps; + static pcre *config_pcre = NULL; static pcre *option_pcre = NULL; static pcre_extra *config_pcre_extra = NULL; @@ -506,6 +508,28 @@ int SigParsePort(Signature *s, const char *portstr, char flag) return 0; } +/** \retval 1 valid + * \retval 0 invalid + */ +static int SigParseActionRejectValidate(void) { +#ifdef HAVE_LIBNET11 +#ifdef HAVE_LIBCAP_NG + if (sc_set_caps == TRUE) { + SCLogError(SC_ERR_LIBNET11_INCOMPATIBLE_WITH_LIBCAP_NG, "Libnet 1.1 is " + "incompatible with POSIX based capabilities with privs dropping. " + "For rejects to work, run as root/super user."); + return 0; + } +#endif +#else /* no libnet 1.1 */ + SCLogError(SC_ERR_LIBNET_REQUIRED_FOR_ACTION, "Libnet 1.1.x is " + "required for action \"%s\" but is not compiled into Suricata", + action); + return 0; +#endif + return 1; +} + /** * \brief Parses the action that has been used by the Signature and allots it * to its Signatue instance. @@ -527,30 +551,26 @@ int SigParseAction(Signature *s, const char *action) { } else if (strcasecmp(action, "pass") == 0) { s->action = ACTION_PASS; return 0; -#ifdef HAVE_LIBNET11 } else if (strcasecmp(action, "reject") == 0) { + if (!(SigParseActionRejectValidate())) + return -1; s->action = ACTION_REJECT; return 0; } else if (strcasecmp(action, "rejectsrc") == 0) { + if (!(SigParseActionRejectValidate())) + return -1; s->action = ACTION_REJECT; return 0; } else if (strcasecmp(action, "rejectdst") == 0) { + if (!(SigParseActionRejectValidate())) + return -1; s->action = ACTION_REJECT_DST; return 0; } else if (strcasecmp(action, "rejectboth") == 0) { + if (!(SigParseActionRejectValidate())) + return -1; s->action = ACTION_REJECT_BOTH; return 0; -#else - } else if (strcasecmp(action, "reject") == 0 || - strcasecmp(action, "rejectsrc") == 0 || - strcasecmp(action, "rejectdst") == 0 || - strcasecmp(action, "rejectboth") == 0) - { - SCLogError(SC_ERR_LIBNET_REQUIRED_FOR_ACTION, "Libnet 1.1.x is " - "required for action \"%s\" but is not compiled into Suricata", - action); - return -1; -#endif /* HAVE_LIBNET11 */ } else { SCLogError(SC_ERR_INVALID_ACTION,"An invalid action \"%s\" was given",action); return -1; @@ -639,7 +659,7 @@ int SigParse(DetectEngineCtx *de_ctx, Signature *s, char *sigstr, uint8_t addrs_ int ret = SigParseBasics(s, sigstr, &basics, addrs_direction); if (ret < 0) { - printf("SigParseBasics failed\n"); + SCLogDebug("SigParseBasics failed"); SCReturnInt(-1); } diff --git a/src/detect.c b/src/detect.c index e1537f24a5..0fa5d420a5 100644 --- a/src/detect.c +++ b/src/detect.c @@ -114,6 +114,7 @@ #include "util-cuda-handlers.h" #include "util-mpm-b2g-cuda.h" #include "util-cuda.h" +#include "util-privs.h" SigMatch *SigMatchAlloc(void); void DetectExitPrintStats(ThreadVars *tv, void *data); @@ -133,6 +134,7 @@ void TmModuleDetectRegister (void) { tmm_modules[TMM_DETECT].ThreadExitPrintStats = DetectExitPrintStats; tmm_modules[TMM_DETECT].ThreadDeinit = DetectThreadDeinit; tmm_modules[TMM_DETECT].RegisterTests = SigRegisterTests; + tmm_modules[TMM_DETECT].cap_flags = 0; } void DetectExitPrintStats(ThreadVars *tv, void *data) { diff --git a/src/flow.c b/src/flow.c index b2aadf2a94..aa00f678cf 100644 --- a/src/flow.c +++ b/src/flow.c @@ -33,6 +33,7 @@ #include "util-byte.h" #include "util-debug.h" +#include "util-privs.h" //#define FLOW_DEFAULT_HASHSIZE 262144 #define FLOW_DEFAULT_HASHSIZE 65536 @@ -651,6 +652,10 @@ void *FlowManagerThread(void *td) SCSetThreadName(th_v->name); SCLogDebug("%s started...", th_v->name); + /* Set the threads capability */ + th_v->cap_flags = 0; + SCDropCaps(th_v); + TmThreadsSetFlag(th_v, THV_INIT_DONE); while (1) { diff --git a/src/log-httplog.c b/src/log-httplog.c index 388d8170d1..a70d7b9b62 100644 --- a/src/log-httplog.c +++ b/src/log-httplog.c @@ -25,6 +25,7 @@ #include "app-layer-htp.h" #include #include "app-layer.h" +#include "util-privs.h" #define DEFAULT_LOG_FILENAME "http.log" @@ -46,6 +47,7 @@ void TmModuleLogHttpLogRegister (void) { tmm_modules[TMM_LOGHTTPLOG].ThreadExitPrintStats = LogHttpLogExitPrintStats; tmm_modules[TMM_LOGHTTPLOG].ThreadDeinit = LogHttpLogThreadDeinit; tmm_modules[TMM_LOGHTTPLOG].RegisterTests = NULL; + tmm_modules[TMM_LOGHTTPLOG].cap_flags = 0; OutputRegisterModule(MODULE_NAME, "http-log", LogHttpLogInitCtx); } diff --git a/src/respond-reject-libnet11.c b/src/respond-reject-libnet11.c index e78dca5455..f1b93340c9 100644 --- a/src/respond-reject-libnet11.c +++ b/src/respond-reject-libnet11.c @@ -31,6 +31,10 @@ #ifdef HAVE_LIBNET11 +/** set to true in main if we're setting caps. We need it here if we're using + * reject rules as libnet 1.1 is not compatible with caps. */ +extern int sc_set_caps; + #include diff --git a/src/respond-reject.c b/src/respond-reject.c index 629d0259c9..57fd70de2f 100644 --- a/src/respond-reject.c +++ b/src/respond-reject.c @@ -24,6 +24,7 @@ #include "respond-reject-libnet11.h" #include "util-debug.h" +#include "util-privs.h" int RejectSendIPv4TCP(ThreadVars *, Packet *, void *); int RejectSendIPv4ICMP(ThreadVars *, Packet *, void *); @@ -37,6 +38,7 @@ void TmModuleRespondRejectRegister (void) { tmm_modules[TMM_RESPONDREJECT].Func = RespondRejectFunc; tmm_modules[TMM_RESPONDREJECT].ThreadDeinit = NULL; tmm_modules[TMM_RESPONDREJECT].RegisterTests = NULL; + tmm_modules[TMM_RESPONDREJECT].cap_flags = 0; /* libnet is not compat with caps */ } TmEcode RespondRejectFunc(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq) { diff --git a/src/runmodes.c b/src/runmodes.c index fc4a16229a..df8c4521fd 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -127,6 +127,7 @@ static void SetupOutputs(ThreadVars *tv) { RunModeOutput *output; TAILQ_FOREACH(output, &RunModeOutputs, entries) { + tv->cap_flags |= output->tm_module->cap_flags; TmVarSlotSetFuncAppend(tv, output->tm_module, output->output_ctx); } } diff --git a/src/source-ipfw.c b/src/source-ipfw.c index e3c42bc970..ad1b72d21e 100644 --- a/src/source-ipfw.c +++ b/src/source-ipfw.c @@ -16,6 +16,7 @@ #include "source-ipfw.h" #include "util-debug.h" #include "conf.h" +#include "util-privs.h" #define IPFW_ACCEPT 0 #define IPFW_DROP 1 @@ -40,6 +41,8 @@ void TmModuleReceiveIPFWRegister (void) { tmm_modules[TMM_RECEIVEIPFW].ThreadExitPrintStats = NULL; tmm_modules[TMM_RECEIVEIPFW].ThreadDeinit = NULL; tmm_modules[TMM_RECEIVEIPFW].RegisterTests = NULL; + tmm_modules[TMM_RECEIVEIPFW].cap_flags = SC_CAP_NET_ADMIN | SC_CAP_NET_RAW | + SC_CAP_NET_BIND_SERVICE | SC_CAP_NET_BROADCAST; /** \todo untested */ } void TmModuleVerdictIPFWRegister (void) { @@ -49,6 +52,8 @@ void TmModuleVerdictIPFWRegister (void) { tmm_modules[TMM_VERDICTIPFW].ThreadExitPrintStats = NULL; tmm_modules[TMM_VERDICTIPFW].ThreadDeinit = NULL; tmm_modules[TMM_VERDICTIPFW].RegisterTests = NULL; + tmm_modules[TMM_VERDICTIPFW].cap_flags = SC_CAP_NET_ADMIN | SC_CAP_NET_RAW | + SC_CAP_NET_BIND_SERVICE; /** \todo untested */ } void TmModuleDecodeIPFWRegister (void) { @@ -58,6 +63,7 @@ void TmModuleDecodeIPFWRegister (void) { tmm_modules[TMM_DECODEIPFW].ThreadExitPrintStats = NULL; tmm_modules[TMM_DECODEIPFW].ThreadDeinit = NULL; tmm_modules[TMM_DECODEIPFW].RegisterTests = NULL; + tmm_modules[TMM_DECODEIPFW].cap_flags = 0; } TmEcode NoIPFWSupportExit(ThreadVars *tv, void *initdata, void **data) { diff --git a/src/source-nfq.c b/src/source-nfq.c index 33514efa35..761ad418e2 100644 --- a/src/source-nfq.c +++ b/src/source-nfq.c @@ -28,6 +28,7 @@ #include "util-debug.h" #include "util-error.h" #include "util-byte.h" +#include "util-privs.h" #ifndef NFQ /** Handle the case where no NFQ support is compiled in. @@ -43,6 +44,7 @@ void TmModuleReceiveNFQRegister (void) { tmm_modules[TMM_RECEIVENFQ].ThreadExitPrintStats = NULL; tmm_modules[TMM_RECEIVENFQ].ThreadDeinit = NULL; tmm_modules[TMM_RECEIVENFQ].RegisterTests = NULL; + tmm_modules[TMM_RECEIVENFQ].cap_flags = SC_CAP_NET_ADMIN; } void TmModuleVerdictNFQRegister (void) { @@ -52,6 +54,7 @@ void TmModuleVerdictNFQRegister (void) { tmm_modules[TMM_VERDICTNFQ].ThreadExitPrintStats = NULL; tmm_modules[TMM_VERDICTNFQ].ThreadDeinit = NULL; tmm_modules[TMM_VERDICTNFQ].RegisterTests = NULL; + tmm_modules[TMM_VERDICTNFQ].cap_flags = SC_CAP_NET_ADMIN; } void TmModuleDecodeNFQRegister (void) { @@ -61,6 +64,7 @@ void TmModuleDecodeNFQRegister (void) { tmm_modules[TMM_DECODENFQ].ThreadExitPrintStats = NULL; tmm_modules[TMM_DECODENFQ].ThreadDeinit = NULL; tmm_modules[TMM_DECODENFQ].RegisterTests = NULL; + tmm_modules[TMM_DECODENFQ].cap_flags = 0; } TmEcode NoNFQSupportExit(ThreadVars *tv, void *initdata, void **data) diff --git a/src/source-pcap-file.c b/src/source-pcap-file.c index f439695d2f..73a58199ad 100644 --- a/src/source-pcap-file.c +++ b/src/source-pcap-file.c @@ -25,6 +25,7 @@ #include "util-debug.h" #include "conf.h" #include "util-error.h" +#include "util-privs.h" extern int max_pending_packets; @@ -66,6 +67,7 @@ void TmModuleReceivePcapFileRegister (void) { tmm_modules[TMM_RECEIVEPCAPFILE].ThreadExitPrintStats = ReceivePcapFileThreadExitStats; tmm_modules[TMM_RECEIVEPCAPFILE].ThreadDeinit = NULL; tmm_modules[TMM_RECEIVEPCAPFILE].RegisterTests = NULL; + tmm_modules[TMM_RECEIVEPCAPFILE].cap_flags = 0; } void TmModuleDecodePcapFileRegister (void) { @@ -75,6 +77,7 @@ void TmModuleDecodePcapFileRegister (void) { tmm_modules[TMM_DECODEPCAPFILE].ThreadExitPrintStats = NULL; tmm_modules[TMM_DECODEPCAPFILE].ThreadDeinit = NULL; tmm_modules[TMM_DECODEPCAPFILE].RegisterTests = NULL; + tmm_modules[TMM_DECODEPCAPFILE].cap_flags = 0; } void PcapFileCallback(char *user, struct pcap_pkthdr *h, u_char *pkt) { diff --git a/src/source-pcap.c b/src/source-pcap.c index 467c3bd4bf..69f3df13cc 100644 --- a/src/source-pcap.c +++ b/src/source-pcap.c @@ -19,6 +19,7 @@ #include "conf.h" #include "util-debug.h" #include "util-error.h" +#include "util-privs.h" extern int max_pending_packets; @@ -63,6 +64,7 @@ void TmModuleReceivePcapRegister (void) { tmm_modules[TMM_RECEIVEPCAP].ThreadExitPrintStats = ReceivePcapThreadExitStats; tmm_modules[TMM_RECEIVEPCAP].ThreadDeinit = NULL; tmm_modules[TMM_RECEIVEPCAP].RegisterTests = NULL; + tmm_modules[TMM_RECEIVEPCAP].cap_flags = SC_CAP_NET_RAW; } /** @@ -76,6 +78,7 @@ void TmModuleDecodePcapRegister (void) { tmm_modules[TMM_DECODEPCAP].ThreadExitPrintStats = NULL; tmm_modules[TMM_DECODEPCAP].ThreadDeinit = NULL; tmm_modules[TMM_DECODEPCAP].RegisterTests = NULL; + tmm_modules[TMM_DECODEPCAP].cap_flags = 0; } /** diff --git a/src/source-pfring.c b/src/source-pfring.c index 0e9492deda..c92731fbb8 100644 --- a/src/source-pfring.c +++ b/src/source-pfring.c @@ -16,6 +16,7 @@ #include "tm-threads.h" #include "source-pfring.h" #include "util-debug.h" +#include "util-privs.h" TmEcode ReceivePfring(ThreadVars *, Packet *, void *, PacketQueue *); TmEcode ReceivePfringThreadInit(ThreadVars *, void *, void **); @@ -39,6 +40,8 @@ void TmModuleReceivePfringRegister (void) { tmm_modules[TMM_RECEIVEPFRING].ThreadExitPrintStats = NULL; tmm_modules[TMM_RECEIVEPFRING].ThreadDeinit = NULL; tmm_modules[TMM_RECEIVEPFRING].RegisterTests = NULL; + tmm_modules[TMM_RECEIVEPFRING].cap_flags = SC_CAP_NET_ADMIN | SC_CAP_NET_RAW | + SC_CAP_NET_BIND_SERVICE | SC_CAP_NET_BROADCAST; } void TmModuleDecodePfringRegister (void) { @@ -48,6 +51,7 @@ void TmModuleDecodePfringRegister (void) { tmm_modules[TMM_DECODEPFRING].ThreadExitPrintStats = NULL; tmm_modules[TMM_DECODEPFRING].ThreadDeinit = NULL; tmm_modules[TMM_DECODEPFRING].RegisterTests = NULL; + tmm_modules[TMM_DECODEPFRING].cap_flags = 0; } /** diff --git a/src/stream-tcp.c b/src/stream-tcp.c index ab07bbb648..493da41052 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -36,6 +36,7 @@ #include "app-layer-parser.h" #include "util-host-os-info.h" +#include "util-privs.h" //#define DEBUG @@ -93,6 +94,7 @@ void TmModuleStreamTcpRegister (void) tmm_modules[TMM_STREAMTCP].ThreadExitPrintStats = StreamTcpExitPrintStats; tmm_modules[TMM_STREAMTCP].ThreadDeinit = StreamTcpThreadDeinit; tmm_modules[TMM_STREAMTCP].RegisterTests = StreamTcpRegisterTests; + tmm_modules[TMM_STREAMTCP].cap_flags = 0; } void StreamTcpIncrMemuse(uint32_t size) { diff --git a/src/suricata.c b/src/suricata.c index 1de76afd0d..4e3e346e09 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -103,6 +103,7 @@ #include "util-cuda-handlers.h" #include "output.h" +#include "util-privs.h" /* * we put this here, because we only use it here in main. @@ -122,12 +123,15 @@ volatile sig_atomic_t sigterm_count = 0; static uint8_t sigflags = 0; -/* Run mode selected */ +/** Run mode selected */ int run_mode = MODE_UNKNOWN; -/* Maximum packets to simultaneously process. */ +/** Maximum packets to simultaneously process. */ intmax_t max_pending_packets; +/** set caps or not */ +int sc_set_caps; + int RunmodeIsUnittests(void) { if (run_mode == MODE_UNITTEST) return 1; @@ -401,10 +405,18 @@ int main(int argc, char **argv) int dump_config = 0; int list_unittests = 0; int daemon = 0; + char *user_name = NULL; + char *group_name = NULL; + uint8_t do_setuid = FALSE; + uint8_t do_setgid = FALSE; + uint32_t userid = 0; + uint32_t groupid = 0; char *log_dir; struct stat buf; + sc_set_caps = FALSE; + #ifdef OS_WIN32 WSADATA wsaData; if (0 != WSAStartup(MAKEWORD(2, 2), &wsaData)) { @@ -431,6 +443,8 @@ int main(int argc, char **argv) {"pidfile", required_argument, 0, 0}, {"init-errors-fatal", 0, 0, 0}, {"fatal-unittests", 0, 0, 0}, + {"user", required_argument, 0, 0}, + {"group", required_argument, 0, 0}, {NULL, 0, NULL, 0} }; @@ -489,6 +503,26 @@ int main(int argc, char **argv) fprintf(stderr, "ERROR: Unit tests not enabled. Make sure to pass --enable-unittests to configure when building.\n"); exit(EXIT_FAILURE); #endif /* UNITTESTS */ + } + else if(strcmp((long_opts[option_index]).name, "user") == 0) { +#ifndef HAVE_LIBCAP_NG + SCLogError(SC_ERR_LIBCAP_NG_REQUIRED, "libcap-ng is required to" + " drop privileges, but it was not compiled into Suricata."); + exit(EXIT_FAILURE); +#else + user_name = optarg; + do_setuid = TRUE; +#endif /* HAVE_LIBCAP_NG */ + } + else if(strcmp((long_opts[option_index]).name, "group") == 0) { +#ifndef HAVE_LIBCAP_NG + SCLogError(SC_ERR_LIBCAP_NG_REQUIRED, "libcap-ng is required to" + " drop privileges, but it was not compiled into Suricata."); + exit(EXIT_FAILURE); +#else + group_name = optarg; + do_setgid = TRUE; +#endif /* HAVE_LIBCAP_NG */ } break; case 'c': @@ -834,6 +868,24 @@ int main(int argc, char **argv) SignalHandlerSetup(SIGHUP, SignalHandlerSighup); #endif /* OS_WIN32 */ + /* Get the suricata user ID to given user ID */ + if (do_setuid == TRUE) { + if (SCGetUserID(user_name, group_name, &userid, &groupid) != 0) { + SCLogError(SC_ERR_UID_FAILED, "failed in getting user ID"); + exit(EXIT_FAILURE); + } + + sc_set_caps = TRUE; + /* Get the suricata group ID to given group ID */ + } else if (do_setgid == TRUE) { + if (SCGetGroupID(group_name, &groupid) != 0) { + SCLogError(SC_ERR_GID_FAILED, "failed in getting group ID"); + exit(EXIT_FAILURE); + } + + sc_set_caps = TRUE; + } + /* pre allocate packets */ SCLogDebug("preallocating packets... packet size %" PRIuMAX "", (uintmax_t)sizeof(Packet)); int i = 0; @@ -875,7 +927,11 @@ int main(int argc, char **argv) memset(&start_time, 0, sizeof(start_time)); gettimeofday(&start_time, NULL); + SCDropMainThreadCaps(userid, groupid); + RunModeInitializeOutputs(); + + /* run the selected runmode */ if (run_mode == MODE_PCAP_DEV) { //RunModeIdsPcap3(de_ctx, pcap_dev); //RunModeIdsPcap2(de_ctx, pcap_dev); diff --git a/src/threadvars.h b/src/threadvars.h index 8103cb1dc0..9c0bd30e8c 100644 --- a/src/threadvars.h +++ b/src/threadvars.h @@ -66,6 +66,8 @@ typedef struct ThreadVars_ { SCMutex *m; SCCondT *cond; + uint8_t cap_flags; /**< Flags to indicate the capabilities of all the + TmModules resgitered under this thread */ struct ThreadVars_ *next; struct ThreadVars_ *prev; } ThreadVars; diff --git a/src/tm-modules.h b/src/tm-modules.h index 214571f625..1711b786f1 100644 --- a/src/tm-modules.h +++ b/src/tm-modules.h @@ -21,6 +21,9 @@ typedef struct TmModule_ { TmEcode (*Func)(ThreadVars *, Packet *, void *, PacketQueue *); void (*RegisterTests)(void); + + uint8_t cap_flags; /**< Flags to indicate the capability requierment of + the given TmModule */ } TmModule; enum { diff --git a/src/tm-threads.c b/src/tm-threads.c index bbc8dadd12..f0cbe62b48 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -19,6 +19,7 @@ #include "util-debug.h" #include #include +#include "util-privs.h" #ifdef OS_FREEBSD #include @@ -131,6 +132,9 @@ void *TmThreadsSlot1NoIn(void *td) { /* Set the thread name */ SCSetThreadName(tv->name); + /* Drop the capabilities for this thread */ + SCDropCaps(tv); + if (tv->thread_setup_flags != 0) TmThreadSetupOptions(tv); @@ -198,6 +202,9 @@ void *TmThreadsSlot1NoOut(void *td) { /* Set the thread name */ SCSetThreadName(tv->name); + /* Drop the capabilities for this thread */ + SCDropCaps(tv); + if (tv->thread_setup_flags != 0) TmThreadSetupOptions(tv); @@ -258,6 +265,9 @@ void *TmThreadsSlot1NoInOut(void *td) { /* Set the thread name */ SCSetThreadName(tv->name); + /* Drop the capabilities for this thread */ + SCDropCaps(tv); + if (tv->thread_setup_flags != 0) TmThreadSetupOptions(tv); @@ -322,6 +332,9 @@ void *TmThreadsSlot1(void *td) { /* Set the thread name */ SCSetThreadName(tv->name); + /* Drop the capabilities for this thread */ + SCDropCaps(tv); + if (tv->thread_setup_flags != 0) TmThreadSetupOptions(tv); @@ -442,6 +455,9 @@ void *TmThreadsSlotVar(void *td) { /* Set the thread name */ SCSetThreadName(tv->name); + /* Drop the capabilities for this thread */ + SCDropCaps(tv); + if (tv->thread_setup_flags != 0) TmThreadSetupOptions(tv); @@ -571,6 +587,7 @@ void Tm1SlotSetFunc(ThreadVars *tv, TmModule *tm, void *data) { s1->s.SlotFunc = tm->Func; s1->s.SlotThreadExitPrintStats = tm->ThreadExitPrintStats; s1->s.SlotThreadDeinit = tm->ThreadDeinit; + tv->cap_flags |= tm->cap_flags; } void TmVarSlotSetFuncAppend(ThreadVars *tv, TmModule *tm, void *data) { @@ -586,6 +603,7 @@ void TmVarSlotSetFuncAppend(ThreadVars *tv, TmModule *tm, void *data) { slot->SlotFunc = tm->Func; slot->SlotThreadExitPrintStats = tm->ThreadExitPrintStats; slot->SlotThreadDeinit = tm->ThreadDeinit; + tv->cap_flags |= tm->cap_flags; if (s->s == NULL) { s->s = slot; diff --git a/src/util-error.c b/src/util-error.c index e71ad4664a..b78a58f57c 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -146,6 +146,11 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_PIDFILE_OPEN); CASE_CODE (SC_ERR_PIDFILE_WRITE); CASE_CODE (SC_ERR_PIDFILE_DAEMON); + CASE_CODE (SC_ERR_UID_FAILED); + CASE_CODE (SC_ERR_GID_FAILED); + CASE_CODE (SC_ERR_CHANGING_CAPS_FAILED); + CASE_CODE (SC_ERR_LIBCAP_NG_REQUIRED); + CASE_CODE (SC_ERR_LIBNET11_INCOMPATIBLE_WITH_LIBCAP_NG); default: return "UNKNOWN_ERROR"; diff --git a/src/util-error.h b/src/util-error.h index 2c6e6a016f..8562630fff 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -162,6 +162,11 @@ typedef enum { SC_ERR_PIDFILE_OPEN, SC_ERR_PIDFILE_WRITE, SC_ERR_PIDFILE_DAEMON, + SC_ERR_UID_FAILED, + SC_ERR_GID_FAILED, + SC_ERR_CHANGING_CAPS_FAILED, + SC_ERR_LIBCAP_NG_REQUIRED, + SC_ERR_LIBNET11_INCOMPATIBLE_WITH_LIBCAP_NG, } SCError; diff --git a/src/util-privs.c b/src/util-privs.c new file mode 100644 index 0000000000..eb2758cc49 --- /dev/null +++ b/src/util-privs.c @@ -0,0 +1,205 @@ +/* Copyright (c) 2010 Open Infomation Security Foundation */ + +/** + * \file + * \author Gurvinder Singh + * + * \brief File to drop the engine capabilities using libcap-ng by + * Steve Grubb + */ + +#include +#include +#include "util-debug.h" +#include "suricata-common.h" + +#ifdef HAVE_LIBCAP_NG + +#include +#include +#include "threadvars.h" +#include "util-cpu.h" +#include "util-privs.h" + +/** flag indicating if we'll be using caps */ +extern int sc_set_caps; + +/** + * \brief Drop all the previliges of the given thread + */ +void SCDropAllCaps() +{ + capng_clear(CAPNG_SELECT_BOTH); + if (capng_apply(CAPNG_SELECT_BOTH) < 0) { + SCLogError(SC_ERR_CHANGING_CAPS_FAILED, "failed in dropping the caps"); + exit(EXIT_FAILURE); + } +} + +/** + * \brief Drop the previliges of the main thread + */ +void SCDropMainThreadCaps(uint32_t userid, uint32_t groupid) +{ + if (sc_set_caps == FALSE) + return; + + capng_clear(CAPNG_SELECT_BOTH); + capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED, + CAP_NET_RAW, /* needed for pcap live mode */ +#ifdef NFQ + CAP_NET_ADMIN, /* needed for nfqueue inline mode */ +#endif + -1); + if (capng_change_id(userid, groupid, CAPNG_DROP_SUPP_GRP | + CAPNG_CLEAR_BOUNDING) < 0) + { + SCLogError(SC_ERR_CHANGING_CAPS_FAILED, "capng_change_id for main thread" + " failed"); + exit(EXIT_FAILURE); + } + + SCLogInfo("dropped the caps for main thread"); +} + +void SCDropCaps(ThreadVars *tv) { +#if 0 + capng_clear(CAPNG_SELECT_BOTH); + capng_apply(CAPNG_SELECT_BOTH); + if (tv->cap_flags & SC_CAP_IPC_LOCK) { + capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_IPC_LOCK); + capng_apply(CAPNG_SELECT_CAPS); + SCLogDebug("For thread \"%s\" CAP_IPC_LOCK has been set", tv->name); + } + if (tv->cap_flags & SC_CAP_NET_ADMIN) { + capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_ADMIN); + capng_apply(CAPNG_SELECT_CAPS); + SCLogDebug("For thread \"%s\" CAP_NET_ADMIN has been set", tv->name); + } + if (tv->cap_flags & SC_CAP_NET_BIND_SERVICE) { + capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_BIND_SERVICE); + capng_apply(CAPNG_SELECT_CAPS); + SCLogDebug("For thread \"%s\" CAP_NET_BIND_SERVICE has been set", tv->name); + } + if (tv->cap_flags & SC_CAP_NET_BROADCAST) { + capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_BROADCAST); + capng_apply(CAPNG_SELECT_CAPS); + SCLogDebug("For thread \"%s\" CAP_NET_BROADCAST has been set", tv->name); + } + if (tv->cap_flags & SC_CAP_NET_RAW) { + capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_RAW); + capng_apply(CAPNG_SELECT_CAPS); + SCLogDebug("For thread \"%s\" CAP_NET_RAW has been set", tv->name); + } + if (tv->cap_flags & SC_CAP_SYS_ADMIN) { + capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_SYS_ADMIN); + capng_apply(CAPNG_SELECT_CAPS); + SCLogDebug("For thread \"%s\" CAP_SYS_ADMIN has been set", tv->name); + } + if (tv->cap_flags & SC_CAP_SYS_RAW_IO) { + capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_SYS_RAWIO); + capng_apply(CAPNG_SELECT_CAPS); + SCLogDebug("For thread \"%s\" CAP_SYS_RAWIO has been set", tv->name); + } +#endif +} + +#endif /* HAVE_LIBCAP_NG */ + +/** + * \brief Function to get the user and group ID from the specified user name + * + * \param user_name pointer to the given user name + * \param uid pointer to the user id in which result will be stored + * \param gid pointer to the group id in which result will be stored + * + * \retval upon success it return 0 + */ +int SCGetUserID(char *user_name, char *group_name, uint32_t *uid, uint32_t *gid) +{ + uint32_t userid = 0; + uint32_t groupid = 0; + struct passwd *pw; + + /* Get the user ID */ + if (isdigit(user_name[0]) != 0) { + userid = atoi(user_name); + pw = getpwuid(userid); + if (pw == NULL) { + SCLogError(SC_ERR_UID_FAILED, "unable to get the user ID, " + "check if user exist!!"); + exit(EXIT_FAILURE); + } + } else { + pw = getpwnam(user_name); + if (pw == NULL) { + SCLogError(SC_ERR_UID_FAILED, "unable to get the user ID, " + "check if user exist!!"); + exit(EXIT_FAILURE); + } + userid = pw->pw_uid; + } + + /* Get the group ID */ + if (group_name != NULL) { + struct group *gp; + + if (isdigit(group_name[0]) != 0) { + groupid = atoi(group_name); + } else { + gp = getgrnam(group_name); + if (gp == NULL) { + SCLogError(SC_ERR_GID_FAILED, "unable to get the group" + " ID, check if group exist!!"); + exit(EXIT_FAILURE); + } + groupid = gp->gr_gid; + } + } else { + groupid = pw->pw_gid; + } + + /* close the group database */ + endgrent(); + /* close the user database */ + endpwent(); + + *uid = userid; + *gid = groupid; + + return 0; +} + +/** + * \brief Function to get the group ID from the specified group name + * + * \param group_name pointer to the given group name + * \param gid pointer to the group id in which result will be stored + * + * \retval upon success it return 0 + */ +int SCGetGroupID(char *group_name, uint32_t *gid) +{ + uint32_t grpid = 0; + struct group *gp; + + /* Get the group ID */ + if (isdigit(group_name[0]) != 0) { + grpid = atoi(group_name); + } else { + gp = getgrnam(group_name); + if (gp == NULL) { + SCLogError(SC_ERR_GID_FAILED, "unable to get the group ID," + " check if group exist!!"); + exit(EXIT_FAILURE); + } + grpid = gp->gr_gid; + } + + /* close the group database */ + endgrent(); + + *gid = grpid; + + return 0; +} diff --git a/src/util-privs.h b/src/util-privs.h new file mode 100644 index 0000000000..1f066a46db --- /dev/null +++ b/src/util-privs.h @@ -0,0 +1,82 @@ +/* Copyright (c) 2010 Open Infomation Security Foundation */ + +/** + * \author Gurvinder Singh + * + */ + +#ifndef _UTIL_PRIVS_H +#define _UTIL_PRIVS_H + +#define SC_CAP_NONE 0x01 +#define SC_CAP_SYS_ADMIN 0x02 +#define SC_CAP_SYS_RAW_IO 0x04 +#define SC_CAP_IPC_LOCK 0x08 +#define SC_CAP_NET_ADMIN 0x10 +#define SC_CAP_NET_RAW 0x20 +#define SC_CAP_NET_BIND_SERVICE 0x40 +#define SC_CAP_NET_BROADCAST 0x80 + +#ifndef HAVE_LIBCAP_NG +#define SCDropCaps(...) +#define SCDropMainThreadCaps(...) +#else +#include "threadvars.h" +#include "util-debug.h" +#include + +/**Drop the previliges of the given thread tv, based on the thread cap_flags + * which implies the capability requirement of the given thread. Initially all + * caps are dropped and later, the required caps are set for the given thread + */ +void SCDropCaps(ThreadVars *tv); +/* +#define SCDropCaps(tv) ({ \ + capng_clear(CAPNG_SELECT_BOTH); \ + capng_apply(CAPNG_SELECT_BOTH); \ + if (tv->cap_flags & SC_CAP_IPC_LOCK) { \ + capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_IPC_LOCK); \ + capng_apply(CAPNG_SELECT_CAPS); \ + SCLogDebug("For thread \"%s\" CAP_IPC_LOCK has been set", tv->name); \ + } \ + if (tv->cap_flags & SC_CAP_NET_ADMIN) { \ + capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_ADMIN); \ + capng_apply(CAPNG_SELECT_CAPS); \ + SCLogDebug("For thread \"%s\" CAP_NET_ADMIN has been set", tv->name); \ + } \ + if (tv->cap_flags & SC_CAP_NET_BIND_SERVICE) { \ + capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_BIND_SERVICE); \ + capng_apply(CAPNG_SELECT_CAPS); \ + SCLogDebug("For thread \"%s\" CAP_NET_BIND_SERVICE has been set", tv->name); \ + } \ + if (tv->cap_flags & SC_CAP_NET_BROADCAST) { \ + capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_BROADCAST); \ + capng_apply(CAPNG_SELECT_CAPS); \ + SCLogDebug("For thread \"%s\" CAP_NET_BROADCAST has been set", tv->name); \ + } \ + if (tv->cap_flags & SC_CAP_NET_RAW) { \ + capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_RAW); \ + capng_apply(CAPNG_SELECT_CAPS); \ + SCLogDebug("For thread \"%s\" CAP_NET_RAW has been set", tv->name); \ + } \ + if (tv->cap_flags & SC_CAP_SYS_ADMIN) { \ + capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_SYS_ADMIN); \ + capng_apply(CAPNG_SELECT_CAPS); \ + SCLogDebug("For thread \"%s\" CAP_SYS_ADMIN has been set", tv->name); \ + } \ + if (tv->cap_flags & SC_CAP_SYS_RAW_IO) { \ + capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_SYS_RAWIO); \ + capng_apply(CAPNG_SELECT_CAPS); \ + SCLogDebug("For thread \"%s\" CAP_SYS_RAWIO has been set", tv->name); \ + } \ +}) +*/ +void SCDropMainThreadCaps(uint32_t , uint32_t ); + +#endif /* HAVE_LIBCAP_NG */ + +int SCGetUserID(char *, char *, uint32_t *, uint32_t *); +int SCGetGroupID(char *, uint32_t *); + +#endif /* _UTIL_PRIVS_H */ +