Coverage Report

Created: 2026-06-07 07:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/src/detect-rfb-secresult.c
Line
Count
Source
1
/* Copyright (C) 2020-2021 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 Sascha Steinbiss <sascha.steinbiss@dcso.de>
22
 */
23
24
#include "suricata-common.h"
25
#include "conf.h"
26
#include "detect.h"
27
#include "detect-parse.h"
28
#include "detect-engine.h"
29
#include "detect-engine-content-inspection.h"
30
#include "detect-rfb-secresult.h"
31
#include "util-unittest.h"
32
33
#include "rust.h"
34
35
34
#define PARSE_REGEX "\\S[A-z]"
36
static DetectParseRegex parse_regex;
37
38
static int rfb_secresult_id = 0;
39
40
static int DetectRfbSecresultMatch(DetectEngineThreadCtx *det_ctx,
41
                                   Flow *f, uint8_t flags, void *state,
42
                                   void *txv, const Signature *s,
43
                                   const SigMatchCtx *ctx);
44
static int DetectRfbSecresultSetup (DetectEngineCtx *, Signature *, const char *);
45
#ifdef UNITTESTS
46
static void RfbSecresultRegisterTests(void);
47
#endif
48
void DetectRfbSecresultFree(DetectEngineCtx *, void *);
49
50
typedef struct DetectRfbSecresultData_ {
51
    uint32_t result; /** result code */
52
} DetectRfbSecresultData;
53
54
/**
55
 * \brief Registration function for rfb.secresult: keyword
56
 */
57
void DetectRfbSecresultRegister (void)
58
34
{
59
34
    sigmatch_table[DETECT_AL_RFB_SECRESULT].name = "rfb.secresult";
60
34
    sigmatch_table[DETECT_AL_RFB_SECRESULT].desc = "match RFB security result";
61
34
    sigmatch_table[DETECT_AL_RFB_SECRESULT].url = "/rules/rfb-keywords.html#rfb-secresult";
62
34
    sigmatch_table[DETECT_AL_RFB_SECRESULT].AppLayerTxMatch = DetectRfbSecresultMatch;
63
34
    sigmatch_table[DETECT_AL_RFB_SECRESULT].Setup = DetectRfbSecresultSetup;
64
34
    sigmatch_table[DETECT_AL_RFB_SECRESULT].Free  = DetectRfbSecresultFree;
65
#ifdef UNITTESTS
66
    sigmatch_table[DETECT_AL_RFB_SECRESULT].RegisterTests = RfbSecresultRegisterTests;
67
#endif
68
34
    DetectSetupParseRegexes(PARSE_REGEX, &parse_regex);
69
70
34
    DetectAppLayerInspectEngineRegister2("rfb.secresult", ALPROTO_RFB, SIG_FLAG_TOCLIENT, 1,
71
34
            DetectEngineInspectGenericList, NULL);
72
73
34
    rfb_secresult_id = DetectBufferTypeGetByName("rfb.secresult");
74
34
}
75
76
enum {
77
    RFB_SECRESULT_OK = 0,
78
    RFB_SECRESULT_FAIL,
79
    RFB_SECRESULT_TOOMANY,
80
    RFB_SECRESULT_UNKNOWN
81
};
82
83
/**
84
 * \struct DetectRfbSecresult_
85
 * DetectRfbSecresult_ is used to store values
86
 */
87
88
struct DetectRfbSecresult_ {
89
    const char *result;
90
    uint16_t code;
91
} results[] = {
92
    { "ok", RFB_SECRESULT_OK, },
93
    { "fail", RFB_SECRESULT_FAIL, },
94
    { "toomany", RFB_SECRESULT_TOOMANY, },
95
    { "unknown", RFB_SECRESULT_UNKNOWN, },
96
    { NULL, 0 },
97
};
98
99
/**
100
 * \internal
101
 * \brief Function to match security result of a RFB TX
102
 *
103
 * \param det_ctx Pointer to the pattern matcher thread.
104
 * \param f       Pointer to the current flow.
105
 * \param flags   Flags.
106
 * \param state   App layer state.
107
 * \param txv     Pointer to the RFBTransaction.
108
 * \param s       Pointer to the Signature.
109
 * \param ctx     Pointer to the sigmatch that we will cast into DetectRfbSecresultData.
110
 *
111
 * \retval 0 no match.
112
 * \retval 1 match.
113
 */
114
static int DetectRfbSecresultMatch(DetectEngineThreadCtx *det_ctx,
115
                                   Flow *f, uint8_t flags, void *state,
116
                                   void *txv, const Signature *s,
117
                                   const SigMatchCtx *ctx)
118
10
{
119
10
    const DetectRfbSecresultData *de = (const DetectRfbSecresultData *)ctx;
120
10
    uint32_t resultcode;
121
10
    int ret = 0;
122
123
10
    if (!de)
124
0
        return 0;
125
126
10
    ret = rs_rfb_tx_get_secresult(txv, &resultcode);
127
10
    if (ret == 0) {
128
10
        return 0;
129
10
    }
130
131
0
    if (de->result < 3) {
132
        /* we are asking for a defined code... */
133
0
        if (resultcode == de->result) {
134
            /* ... which needs to match */
135
0
            return 1;
136
0
        }
137
0
    } else {
138
        /* we are asking for an unknown code */
139
0
        if (resultcode > 2) {
140
            /* match any unknown code */
141
0
            return 1;
142
0
        }
143
0
    }
144
145
0
    return 0;
146
0
}
147
148
/**
149
 * \internal
150
 * \brief This function is used to parse options passed via rfb.secresults: keyword
151
 *
152
 * \param rawstr Pointer to the user provided secresult options
153
 *
154
 * \retval de pointer to DetectRfbSecresultData on success
155
 * \retval NULL on failure
156
 */
157
static DetectRfbSecresultData *DetectRfbSecresultParse (const char *rawstr)
158
1.92k
{
159
1.92k
    int i;
160
1.92k
    DetectRfbSecresultData *de = NULL;
161
1.92k
    int found = 0;
162
163
1.92k
    pcre2_match_data *match = NULL;
164
1.92k
    int ret = DetectParsePcreExec(&parse_regex, &match, rawstr, 0, 0);
165
1.92k
    if (ret < 1) {
166
12
        SCLogError("pcre_exec parse error, ret %" PRId32 ", string %s", ret, rawstr);
167
12
        goto error;
168
12
    }
169
170
4.59k
    for(i = 0; results[i].result != NULL; i++)  {
171
3.97k
        if((strcasecmp(results[i].result,rawstr)) == 0) {
172
1.29k
            found = 1;
173
1.29k
            break;
174
1.29k
        }
175
3.97k
    }
176
177
1.91k
    if(found == 0) {
178
621
        SCLogError("unknown secresult value %s", rawstr);
179
621
        goto error;
180
621
    }
181
182
1.29k
    de = SCMalloc(sizeof(DetectRfbSecresultData));
183
1.29k
    if (unlikely(de == NULL))
184
0
        goto error;
185
186
1.29k
    de->result = results[i].code;
187
188
1.29k
    pcre2_match_data_free(match);
189
1.29k
    return de;
190
191
633
error:
192
633
    if (match) {
193
633
        pcre2_match_data_free(match);
194
633
    }
195
633
    if (de) SCFree(de);
196
633
    return NULL;
197
1.29k
}
198
199
/**
200
 * \internal
201
 * \brief this function is used to add the parsed secresult into the current signature
202
 *
203
 * \param de_ctx pointer to the Detection Engine Context
204
 * \param s pointer to the Current Signature
205
 * \param rawstr pointer to the user provided secresult options
206
 *
207
 * \retval 0 on Success
208
 * \retval -1 on Failure
209
 */
210
static int DetectRfbSecresultSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
211
1.96k
{
212
1.96k
    DetectRfbSecresultData *de = NULL;
213
1.96k
    SigMatch *sm = NULL;
214
215
1.96k
    if (DetectSignatureSetAppProto(s, ALPROTO_RFB) < 0)
216
41
        return -1;
217
218
1.92k
    de = DetectRfbSecresultParse(rawstr);
219
1.92k
    if (de == NULL)
220
633
        goto error;
221
222
1.29k
    sm = SigMatchAlloc();
223
1.29k
    if (sm == NULL)
224
0
        goto error;
225
226
1.29k
    sm->type = DETECT_AL_RFB_SECRESULT;
227
1.29k
    sm->ctx = (SigMatchCtx *)de;
228
229
1.29k
    SigMatchAppendSMToList(s, sm, rfb_secresult_id);
230
231
1.29k
    return 0;
232
233
633
error:
234
633
    if (de) SCFree(de);
235
633
    if (sm) SCFree(sm);
236
633
    return -1;
237
1.29k
}
238
239
/**
240
 * \internal
241
 * \brief this function will free memory associated with DetectRfbSecresultData
242
 *
243
 * \param de pointer to DetectRfbSecresultData
244
 */
245
void DetectRfbSecresultFree(DetectEngineCtx *de_ctx, void *de_ptr)
246
1.29k
{
247
1.29k
    DetectRfbSecresultData *de = (DetectRfbSecresultData *)de_ptr;
248
1.29k
    if(de) SCFree(de);
249
1.29k
}
250
251
/*
252
 * ONLY TESTS BELOW THIS COMMENT
253
 */
254
255
#ifdef UNITTESTS
256
/**
257
 * \test RfbSecresultTestParse01 is a test for a valid secresult value
258
 */
259
static int RfbSecresultTestParse01 (void)
260
{
261
    DetectRfbSecresultData *de = DetectRfbSecresultParse("fail");
262
263
    FAIL_IF_NULL(de);
264
265
    DetectRfbSecresultFree(NULL, de);
266
267
    PASS;
268
}
269
270
/**
271
 * \test RfbSecresultTestParse02 is a test for an invalid secresult value
272
 */
273
static int RfbSecresultTestParse02 (void)
274
{
275
    DetectRfbSecresultData *de = DetectRfbSecresultParse("invalidopt");
276
277
    FAIL_IF_NOT_NULL(de);
278
279
    PASS;
280
}
281
282
/**
283
 * \brief this function registers unit tests for RfbSecresult
284
 */
285
void RfbSecresultRegisterTests(void)
286
{
287
    UtRegisterTest("RfbSecresultTestParse01", RfbSecresultTestParse01);
288
    UtRegisterTest("RfbSecresultTestParse02", RfbSecresultTestParse02);
289
}
290
#endif /* UNITTESTS */