Coverage Report

Created: 2025-07-23 07:29

/src/suricata7/src/detect-krb5-errcode.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2018-2020 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 Pierre Chifflier <chifflier@wzdftpd.net>
22
 */
23
24
#include "suricata-common.h"
25
#include "util-unittest.h"
26
#include "util-byte.h"
27
28
#include "detect-parse.h"
29
#include "detect-engine.h"
30
31
#include "detect-krb5-errcode.h"
32
33
#include "app-layer-krb5.h"
34
#include "rust.h"
35
36
/**
37
 * \brief Regex for parsing our keyword options
38
 */
39
73
#define PARSE_REGEX  "^\\s*([A-z0-9\\.]+|\"[A-z0-9_\\.]+\")\\s*$"
40
static DetectParseRegex parse_regex;
41
42
/* Prototypes of functions registered in DetectKrb5ErrCodeRegister below */
43
static int DetectKrb5ErrCodeMatch (DetectEngineThreadCtx *, Flow *,
44
                                   uint8_t, void *, void *, const Signature *,
45
                                   const SigMatchCtx *);
46
static int DetectKrb5ErrCodeSetup (DetectEngineCtx *, Signature *, const char *);
47
static void DetectKrb5ErrCodeFree (DetectEngineCtx *, void *);
48
#ifdef UNITTESTS
49
static void DetectKrb5ErrCodeRegisterTests (void);
50
#endif
51
52
static int g_krb5_err_code_list_id = 0;
53
54
/**
55
 * \brief Registration function for krb5_err_code: keyword
56
 *
57
 * This function is called once in the 'lifetime' of the engine.
58
 */
59
void DetectKrb5ErrCodeRegister(void)
60
73
{
61
73
    sigmatch_table[DETECT_AL_KRB5_ERRCODE].name = "krb5_err_code";
62
73
    sigmatch_table[DETECT_AL_KRB5_ERRCODE].desc = "match Kerberos 5 error code";
63
73
    sigmatch_table[DETECT_AL_KRB5_ERRCODE].url = "/rules/kerberos-keywords.html#krb5-err-code";
64
73
    sigmatch_table[DETECT_AL_KRB5_ERRCODE].Match = NULL;
65
73
    sigmatch_table[DETECT_AL_KRB5_ERRCODE].AppLayerTxMatch = DetectKrb5ErrCodeMatch;
66
73
    sigmatch_table[DETECT_AL_KRB5_ERRCODE].Setup = DetectKrb5ErrCodeSetup;
67
73
    sigmatch_table[DETECT_AL_KRB5_ERRCODE].Free = DetectKrb5ErrCodeFree;
68
#ifdef UNITTESTS
69
    sigmatch_table[DETECT_AL_KRB5_ERRCODE].RegisterTests = DetectKrb5ErrCodeRegisterTests;
70
#endif
71
72
73
    DetectAppLayerInspectEngineRegister2("krb5_err_code", ALPROTO_KRB5, SIG_FLAG_TOSERVER, 0,
73
73
            DetectEngineInspectGenericList, NULL);
74
75
73
    DetectAppLayerInspectEngineRegister2("krb5_err_code", ALPROTO_KRB5, SIG_FLAG_TOCLIENT, 0,
76
73
            DetectEngineInspectGenericList, NULL);
77
78
    /* set up the PCRE for keyword parsing */
79
73
    DetectSetupParseRegexes(PARSE_REGEX, &parse_regex);
80
81
73
    g_krb5_err_code_list_id = DetectBufferTypeRegister("krb5_err_code");
82
73
    SCLogDebug("g_krb5_err_code_list_id %d", g_krb5_err_code_list_id);
83
73
}
84
85
/**
86
 * \brief This function is used to match KRB5 rule option on a packet
87
 *
88
 * \param t pointer to thread vars
89
 * \param det_ctx pointer to the pattern matcher thread
90
 * \param p pointer to the current packet
91
 * \param m pointer to the sigmatch with context that we will cast into DetectKrb5Data
92
 *
93
 * \retval 0 no match
94
 * \retval 1 match
95
 */
96
static int DetectKrb5ErrCodeMatch (DetectEngineThreadCtx *det_ctx,
97
                                   Flow *f, uint8_t flags, void *state,
98
                                   void *txv, const Signature *s,
99
                                   const SigMatchCtx *ctx)
100
0
{
101
0
    int32_t err_code;
102
0
    int ret;
103
0
    const DetectKrb5ErrCodeData *dd = (const DetectKrb5ErrCodeData *)ctx;
104
105
0
    SCEnter();
106
107
0
    ret = rs_krb5_tx_get_errcode(txv, &err_code);
108
0
    if (ret != 0)
109
0
        SCReturnInt(0);
110
111
0
    if (dd->err_code == err_code)
112
0
        SCReturnInt(1);
113
114
0
    SCReturnInt(0);
115
0
}
116
117
/**
118
 * \brief This function is used to parse options passed via krb5_errcode: keyword
119
 *
120
 * \param krb5str Pointer to the user provided krb5_err_code options
121
 *
122
 * \retval krb5d pointer to DetectKrb5Data on success
123
 * \retval NULL on failure
124
 */
125
static DetectKrb5ErrCodeData *DetectKrb5ErrCodeParse (const char *krb5str)
126
205
{
127
205
    DetectKrb5ErrCodeData *krb5d = NULL;
128
205
    char arg1[4] = "";
129
205
    int res = 0;
130
205
    size_t pcre2len;
131
132
205
    pcre2_match_data *match = NULL;
133
205
    int ret = DetectParsePcreExec(&parse_regex, &match, krb5str, 0, 0);
134
205
    if (ret != 2) {
135
8
        SCLogError("parse error, ret %" PRId32 "", ret);
136
8
        goto error;
137
8
    }
138
139
197
    pcre2len = sizeof(arg1);
140
197
    res = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)arg1, &pcre2len);
141
197
    if (res < 0) {
142
2
        SCLogError("pcre2_substring_copy_bynumber failed");
143
2
        goto error;
144
2
    }
145
146
195
    krb5d = SCMalloc(sizeof (DetectKrb5ErrCodeData));
147
195
    if (unlikely(krb5d == NULL))
148
0
        goto error;
149
195
    if (StringParseInt32(&krb5d->err_code, 10, 0,
150
195
                         (const char *)arg1) < 0) {
151
1
        goto error;
152
1
    }
153
194
    pcre2_match_data_free(match);
154
194
    return krb5d;
155
156
11
error:
157
11
    if (match) {
158
11
        pcre2_match_data_free(match);
159
11
    }
160
11
    if (krb5d)
161
1
        SCFree(krb5d);
162
11
    return NULL;
163
195
}
164
165
/**
166
 * \brief parse the options from the 'krb5_err_code' keyword in the rule into
167
 *        the Signature data structure.
168
 *
169
 * \param de_ctx pointer to the Detection Engine Context
170
 * \param s pointer to the Current Signature
171
 * \param krb5str pointer to the user provided options
172
 *
173
 * \retval 0 on Success
174
 * \retval -1 on Failure
175
 */
176
static int DetectKrb5ErrCodeSetup (DetectEngineCtx *de_ctx, Signature *s, const char *krb5str)
177
6
{
178
6
    DetectKrb5ErrCodeData *krb5d = NULL;
179
6
    SigMatch *sm = NULL;
180
181
6
    if (DetectSignatureSetAppProto(s, ALPROTO_KRB5) != 0)
182
3
        return -1;
183
184
3
    krb5d = DetectKrb5ErrCodeParse(krb5str);
185
3
    if (krb5d == NULL)
186
3
        goto error;
187
188
0
    sm = SigMatchAlloc();
189
0
    if (sm == NULL)
190
0
        goto error;
191
192
0
    sm->type = DETECT_AL_KRB5_ERRCODE;
193
0
    sm->ctx = (void *)krb5d;
194
195
0
    SigMatchAppendSMToList(s, sm, g_krb5_err_code_list_id);
196
197
0
    return 0;
198
199
3
error:
200
3
    if (krb5d != NULL)
201
0
        DetectKrb5ErrCodeFree(de_ctx, krb5d);
202
3
    if (sm != NULL)
203
0
        SCFree(sm);
204
3
    return -1;
205
0
}
206
207
/**
208
 * \brief this function will free memory associated with DetectKrb5Data
209
 *
210
 * \param ptr pointer to DetectKrb5Data
211
 */
212
194
static void DetectKrb5ErrCodeFree(DetectEngineCtx *de_ctx, void *ptr) {
213
194
    DetectKrb5ErrCodeData *krb5d = (DetectKrb5ErrCodeData *)ptr;
214
215
194
    SCFree(krb5d);
216
194
}
217
218
#ifdef UNITTESTS
219
/**
220
 * \test description of the test
221
 */
222
223
static int DetectKrb5ErrCodeParseTest01 (void)
224
{
225
    DetectKrb5ErrCodeData *krb5d = DetectKrb5ErrCodeParse("10");
226
    FAIL_IF_NULL(krb5d);
227
    FAIL_IF(!(krb5d->err_code == 10));
228
    DetectKrb5ErrCodeFree(NULL, krb5d);
229
    PASS;
230
}
231
232
static int DetectKrb5ErrCodeSignatureTest01 (void)
233
{
234
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
235
    FAIL_IF_NULL(de_ctx);
236
237
    Signature *sig = DetectEngineAppendSig(de_ctx, "alert krb5 any any -> any any (krb5_err_code:10; sid:1; rev:1;)");
238
    FAIL_IF_NULL(sig);
239
240
    DetectEngineCtxFree(de_ctx);
241
    PASS;
242
}
243
244
/**
245
 * \brief this function registers unit tests for DetectKrb5ErrCode
246
 */
247
static void DetectKrb5ErrCodeRegisterTests(void)
248
{
249
    UtRegisterTest("DetectKrb5ErrCodeParseTest01", DetectKrb5ErrCodeParseTest01);
250
    UtRegisterTest("DetectKrb5ErrCodeSignatureTest01",
251
                   DetectKrb5ErrCodeSignatureTest01);
252
}
253
#endif /* UNITTESTS */