Coverage Report

Created: 2026-03-31 07:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/src/util-privs.c
Line
Count
Source
1
/* Copyright (C) 2007-2010 Open Information Security Foundation
2
 *
3
 * You can copy, redistribute or modify this Program under the terms of
4
 * the GNU General Public License version 2 as published by the Free
5
 * Software Foundation.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * version 2 along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15
 * 02110-1301, USA.
16
 */
17
18
/**
19
 * \file
20
 *
21
 * \author  Gurvinder Singh <gurvindersinghdahiya@gmail.com>
22
 *
23
 * File to drop the engine capabilities using libcap-ng by
24
 * Steve Grubb
25
 */
26
27
#ifndef OS_WIN32
28
29
#include "suricata-common.h"
30
#include "util-debug.h"
31
#include "suricata.h"
32
33
#include "util-privs.h"
34
#include "util-byte.h"
35
36
#ifdef HAVE_LIBCAP_NG
37
38
#include <cap-ng.h>
39
#ifdef HAVE_SYS_PRCTL_H
40
#include <sys/prctl.h>
41
#endif
42
#include "threadvars.h"
43
#include "util-cpu.h"
44
#include "runmodes.h"
45
46
/** flag indicating if we'll be using caps */
47
extern int sc_set_caps;
48
49
/** our current runmode */
50
extern int run_mode;
51
52
/**
53
 * \brief   Drop the privileges of the main thread
54
 */
55
void SCDropMainThreadCaps(uint32_t userid, uint32_t groupid)
56
{
57
    if (sc_set_caps == FALSE)
58
        return;
59
60
    capng_clear(CAPNG_SELECT_BOTH);
61
62
    switch (run_mode) {
63
        case RUNMODE_PCAP_DEV:
64
        case RUNMODE_AFP_DEV:
65
        case RUNMODE_AFXDP_DEV:
66
            capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED,
67
                    CAP_NET_RAW,            /* needed for pcap live mode */
68
                    CAP_SYS_NICE,
69
                    CAP_NET_ADMIN,
70
                    -1);
71
            break;
72
        case RUNMODE_PFRING:
73
            capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED,
74
                    CAP_NET_ADMIN, CAP_NET_RAW, CAP_SYS_NICE,
75
                    -1);
76
            break;
77
        case RUNMODE_NFLOG:
78
        case RUNMODE_NFQ:
79
            capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED,
80
                    CAP_NET_ADMIN,          /* needed for nflog and nfqueue inline mode */
81
                    CAP_SYS_NICE,
82
                    -1);
83
            break;
84
    }
85
86
    if (capng_change_id(userid, groupid, CAPNG_DROP_SUPP_GRP |
87
            CAPNG_CLEAR_BOUNDING) < 0)
88
    {
89
        FatalError("capng_change_id for main thread"
90
                   " failed");
91
    }
92
93
    SCLogInfo("dropped the caps for main thread");
94
}
95
96
void SCDropCaps(ThreadVars *tv)
97
{
98
#if 0
99
    capng_clear(CAPNG_SELECT_BOTH);
100
    capng_apply(CAPNG_SELECT_BOTH);
101
    if (tv->cap_flags & SC_CAP_IPC_LOCK) {
102
        capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_IPC_LOCK);
103
        capng_apply(CAPNG_SELECT_CAPS);
104
        SCLogDebug("For thread \"%s\" CAP_IPC_LOCK has been set", tv->name);
105
    }
106
    if (tv->cap_flags & SC_CAP_NET_ADMIN) {
107
        capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_ADMIN);
108
        capng_apply(CAPNG_SELECT_CAPS);
109
        SCLogDebug("For thread \"%s\" CAP_NET_ADMIN has been set", tv->name);
110
    }
111
    if (tv->cap_flags & SC_CAP_NET_BIND_SERVICE) {
112
        capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_BIND_SERVICE);
113
        capng_apply(CAPNG_SELECT_CAPS);
114
        SCLogDebug("For thread \"%s\" CAP_NET_BIND_SERVICE has been set", tv->name);
115
    }
116
    if (tv->cap_flags & SC_CAP_NET_BROADCAST) {
117
        capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_BROADCAST);
118
        capng_apply(CAPNG_SELECT_CAPS);
119
        SCLogDebug("For thread \"%s\" CAP_NET_BROADCAST has been set", tv->name);
120
    }
121
    if (tv->cap_flags & SC_CAP_NET_RAW) {
122
        capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_RAW);
123
        capng_apply(CAPNG_SELECT_CAPS);
124
        SCLogDebug("For thread \"%s\" CAP_NET_RAW has been set", tv->name);
125
    }
126
    if (tv->cap_flags & SC_CAP_SYS_ADMIN) {
127
        capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_SYS_ADMIN);
128
        capng_apply(CAPNG_SELECT_CAPS);
129
        SCLogDebug("For thread \"%s\" CAP_SYS_ADMIN has been set", tv->name);
130
    }
131
    if (tv->cap_flags & SC_CAP_SYS_RAW_IO) {
132
        capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_SYS_RAWIO);
133
        capng_apply(CAPNG_SELECT_CAPS);
134
        SCLogDebug("For thread \"%s\" CAP_SYS_RAWIO has been set", tv->name);
135
    }
136
#endif
137
}
138
139
#endif /* HAVE_LIBCAP_NG */
140
141
/**
142
 * \brief   Function to get the user and group ID from the specified user name
143
 *
144
 * \param   user_name   pointer to the given user name
145
 * \param   uid         pointer to the user id in which result will be stored
146
 * \param   gid         pointer to the group id in which result will be stored
147
 *
148
 * \retval  FatalError on a failure
149
 */
150
void SCGetUserID(const char *user_name, const char *group_name, uint32_t *uid, uint32_t *gid)
151
0
{
152
0
    uint32_t userid = 0;
153
0
    uint32_t groupid = 0;
154
0
    struct passwd *pw;
155
156
0
    if (user_name == NULL || strlen(user_name) == 0) {
157
0
        FatalError("no user name was provided - ensure it is specified either in the configuration "
158
0
                   "file (run-as.user) or in command-line arguments (--user)");
159
0
    }
160
161
    /* Get the user ID */
162
0
    if (isdigit((unsigned char)user_name[0]) != 0) {
163
0
        if (ByteExtractStringUint32(&userid, 10, 0, (const char *)user_name) < 0) {
164
0
            FatalError("invalid user id value: '%s'", user_name);
165
0
        }
166
0
        pw = getpwuid(userid);
167
0
       if (pw == NULL) {
168
0
           FatalError("unable to get the user ID, "
169
0
                      "check if user exist!!");
170
0
        }
171
0
    } else {
172
0
        pw = getpwnam(user_name);
173
0
        if (pw == NULL) {
174
0
            FatalError("unable to get the user ID, "
175
0
                       "check if user exist!!");
176
0
        }
177
0
        userid = pw->pw_uid;
178
0
    }
179
180
    /* Get the group ID */
181
0
    if (group_name != NULL) {
182
0
        struct group *gp;
183
184
0
        if (isdigit((unsigned char)group_name[0]) != 0) {
185
0
            if (ByteExtractStringUint32(&groupid, 10, 0, (const char *)group_name) < 0) {
186
0
                FatalError("invalid group id: '%s'", group_name);
187
0
            }
188
0
        } else {
189
0
            gp = getgrnam(group_name);
190
0
            if (gp == NULL) {
191
0
                FatalError("unable to get the group"
192
0
                           " ID, check if group exist!!");
193
0
            }
194
0
            groupid = gp->gr_gid;
195
0
        }
196
0
    } else {
197
0
        groupid = pw->pw_gid;
198
0
    }
199
200
    /* close the group database */
201
0
    endgrent();
202
    /* close the user database */
203
0
    endpwent();
204
205
0
    *uid = userid;
206
0
    *gid = groupid;
207
0
}
208
209
/**
210
 * \brief   Function to get the group ID from the specified group name
211
 *
212
 * \param   group_name  pointer to the given group name
213
 * \param   gid         pointer to the group id in which result will be stored
214
 *
215
 * \retval  FatalError on a failure
216
 */
217
void SCGetGroupID(const char *group_name, uint32_t *gid)
218
0
{
219
0
    uint32_t grpid = 0;
220
0
    struct group *gp;
221
222
0
    if (group_name == NULL || strlen(group_name) == 0) {
223
0
        FatalError("no group name was provided - ensure it is specified either in the "
224
0
                   "configuration file (run-as.group) or in command-line arguments (--group)");
225
0
    }
226
227
    /* Get the group ID */
228
0
    if (isdigit((unsigned char)group_name[0]) != 0) {
229
0
        if (ByteExtractStringUint32(&grpid, 10, 0, (const char *)group_name) < 0) {
230
0
            FatalError("invalid group id: '%s'", group_name);
231
0
        }
232
0
    } else {
233
0
        gp = getgrnam(group_name);
234
0
        if (gp == NULL) {
235
0
            FatalError("unable to get the group ID,"
236
0
                       " check if group exist!!");
237
0
        }
238
0
        grpid = gp->gr_gid;
239
0
    }
240
241
    /* close the group database */
242
0
    endgrent();
243
244
0
    *gid = grpid;
245
0
}
246
247
#ifdef __OpenBSD__
248
int SCPledge(void)
249
{
250
    int ret = pledge("stdio rpath wpath cpath fattr unix dns bpf", NULL);
251
252
    if (ret != 0) {
253
        SCLogError("unable to pledge,"
254
                   " check permissions!! ret=%i errno=%i",
255
                ret, errno);
256
        exit(EXIT_FAILURE);
257
    }
258
259
    return 0;
260
}
261
#endif /* __OpenBSD__ */
262
#endif /* OS_WIN32 */