/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 */ |