]> git.ipfire.org Git - people/ms/suricata.git/blame - src/app-layer-smtp.c
Fix duplicate packet decoder events. Add event entries that were missing as well.
[people/ms/suricata.git] / src / app-layer-smtp.c
CommitLineData
7fa22e84 1/* Copyright (C) 2007-2012 Open Information Security Foundation
576ec7da
AS
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 *
420befb1 21 * \author Anoop Saldanha <anoopsaldanha@gmail.com>
576ec7da
AS
22 */
23
24#include "suricata.h"
25#include "suricata-common.h"
26#include "debug.h"
27#include "decode.h"
28#include "threads.h"
29
30#include "stream-tcp-private.h"
31#include "stream-tcp-reassemble.h"
32#include "stream-tcp.h"
33#include "stream.h"
34
35#include "app-layer-protos.h"
36#include "app-layer-parser.h"
37#include "app-layer-smtp.h"
38
39#include "util-debug.h"
40#include "util-byte.h"
41#include "util-unittest.h"
42#include "util-byte.h"
43#include "util-unittest-helper.h"
44#include "util-memcmp.h"
45#include "flow-util.h"
46
47#include "detect-engine.h"
48#include "detect-engine-state.h"
49#include "detect-parse.h"
50
51#include "conf.h"
5311cd48 52#include "decode-events.h"
576ec7da 53
576ec7da
AS
54#define SMTP_MAX_REQUEST_AND_REPLY_LINE_LENGTH 510
55
56#define SMTP_COMMAND_BUFFER_STEPS 5
57
58/* we are in process of parsing a fresh command. Just a placeholder. If we
59 * are not in STATE_COMMAND_DATA_MODE, we have to be in this mode */
60#define SMTP_PARSER_STATE_COMMAND_MODE 0x00
61/* we are in mode of parsing a command's data. Used when we are parsing tls
62 * or accepting the rfc 2822 mail after DATA command */
63#define SMTP_PARSER_STATE_COMMAND_DATA_MODE 0x01
64/* Used when we are still in the process of parsing a server command. Used
65 * with multi-line replies and the stream is fragmented before all the lines
66 * for a response is seen */
67#define SMTP_PARSER_STATE_PARSING_SERVER_RESPONSE 0x02
68/* Used to indicate that the parser has seen the first reply */
69#define SMTP_PARSER_STATE_FIRST_REPLY_SEEN 0x04
70/* Used to indicate that the parser is parsing a multiline reply */
71#define SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY 0x08
72
73/* Various SMTP commands
74 * We currently have var-ified just STARTTLS and DATA, since we need to them
75 * for state transitions. The rest are just indicate as OTHER_CMD. Other
76 * commands would be introduced as and when needed */
77#define SMTP_COMMAND_STARTTLS 1
78#define SMTP_COMMAND_DATA 2
d3ca65de 79#define SMTP_COMMAND_BDAT 3
576ec7da
AS
80/* not an actual command per se, but the mode where we accept the mail after
81 * DATA has it's own reply code for completion, from the server. We give this
82 * stage a pseudo command of it's own, so that we can add this to the command
83 * buffer to match with the reply */
d3ca65de 84#define SMTP_COMMAND_DATA_MODE 4
576ec7da 85/* All other commands are represented by this var */
d3ca65de 86#define SMTP_COMMAND_OTHER_CMD 5
576ec7da
AS
87
88/* Different EHLO extensions. Not used now. */
89#define SMTP_EHLO_EXTENSION_PIPELINING
90#define SMTP_EHLO_EXTENSION_SIZE
91#define SMTP_EHLO_EXTENSION_DSN
92#define SMTP_EHLO_EXTENSION_STARTTLS
93#define SMTP_EHLO_EXTENSION_8BITMIME
94
5311cd48
AS
95SCEnumCharMap smtp_decoder_event_table[ ] = {
96 { "INVALID_REPLY", SMTP_DECODER_EVENT_INVALID_REPLY },
97 { "UNABLE_TO_MATCH_REPLY_WITH_REQUEST",
98 SMTP_DECODER_EVENT_UNABLE_TO_MATCH_REPLY_WITH_REQUEST },
99 { "MAX_COMMAND_LINE_LEN_EXCEEDED",
100 SMTP_DECODER_EVENT_MAX_COMMAND_LINE_LEN_EXCEEDED },
101 { "MAX_REPLY_LINE_LEN_EXCEEDED",
102 SMTP_DECODER_EVENT_MAX_REPLY_LINE_LEN_EXCEEDED },
103 { "INVALID_PIPELINED_SEQUENCE",
104 SMTP_DECODER_EVENT_INVALID_PIPELINED_SEQUENCE },
105 { "BDAT_CHUNK_LEN_EXCEEDED",
106 SMTP_DECODER_EVENT_BDAT_CHUNK_LEN_EXCEEDED },
107 { "NO_SERVER_WELCOME_MESSAGE",
108 SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE },
109 { "TLS_REJECTED",
110 SMTP_DECODER_EVENT_TLS_REJECTED },
111 { "DATA_COMMAND_REJECTED",
112 SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED },
113 { NULL, -1 },
114};
4d38a571 115
e05034f5 116#define SMTP_MPM DEFAULT_MPM
4d38a571
AS
117
118static MpmCtx *smtp_mpm_ctx = NULL;
119MpmThreadCtx *smtp_mpm_thread_ctx;
120
121/* smtp reply codes. If an entry is made here, please make a simultaneous
122 * entry in smtp_reply_map */
123enum {
124 SMTP_REPLY_211,
125 SMTP_REPLY_214,
126 SMTP_REPLY_220,
127 SMTP_REPLY_221,
128 SMTP_REPLY_250,
129 SMTP_REPLY_251,
130 SMTP_REPLY_252,
131
132 SMTP_REPLY_354,
133
134 SMTP_REPLY_421,
135 SMTP_REPLY_450,
136 SMTP_REPLY_451,
137 SMTP_REPLY_452,
138 SMTP_REPLY_455,
139
140 SMTP_REPLY_500,
141 SMTP_REPLY_501,
142 SMTP_REPLY_502,
143 SMTP_REPLY_503,
144 SMTP_REPLY_504,
145 SMTP_REPLY_550,
146 SMTP_REPLY_551,
147 SMTP_REPLY_552,
148 SMTP_REPLY_553,
149 SMTP_REPLY_554,
150 SMTP_REPLY_555,
151};
152
153SCEnumCharMap smtp_reply_map[ ] = {
154 { "211", SMTP_REPLY_211 },
155 { "214", SMTP_REPLY_214 },
156 { "220", SMTP_REPLY_220 },
157 { "221", SMTP_REPLY_221 },
158 { "250", SMTP_REPLY_250 },
159 { "251", SMTP_REPLY_251 },
160 { "252", SMTP_REPLY_252 },
161
162 { "354", SMTP_REPLY_354 },
163
164 { "421", SMTP_REPLY_421 },
165 { "450", SMTP_REPLY_450 },
166 { "451", SMTP_REPLY_451 },
167 { "452", SMTP_REPLY_452 },
168 { "455", SMTP_REPLY_455 },
169
170 { "500", SMTP_REPLY_500 },
171 { "501", SMTP_REPLY_501 },
172 { "502", SMTP_REPLY_502 },
173 { "503", SMTP_REPLY_503 },
174 { "504", SMTP_REPLY_504 },
175 { "550", SMTP_REPLY_550 },
176 { "551", SMTP_REPLY_551 },
177 { "552", SMTP_REPLY_552 },
178 { "553", SMTP_REPLY_553 },
179 { "554", SMTP_REPLY_554 },
180 { "555", SMTP_REPLY_555 },
181 { NULL, -1 },
182};
576ec7da
AS
183//static void SMTPParserReset(void)
184//{
185// return;
186//}
187
188/**
189 * \internal
190 * \brief Get the next line from input. It doesn't do any length validation.
191 *
192 * \param state The smtp state.
193 *
194 * \retval 0 On suceess.
195 * \retval -1 Either when we don't have any new lines to supply anymore or
196 * on failure.
197 */
198static int SMTPGetLine(SMTPState *state)
199{
7b0f261f
VJ
200 SCEnter();
201
88115902
AS
202 /* we have run out of input */
203 if (state->input_len <= 0)
576ec7da
AS
204 return -1;
205
88115902
AS
206 /* toserver */
207 if (state->direction == 0) {
208 if (state->ts_current_line_lf_seen == 1) {
209 /* we have seen the lf for the previous line. Clear the parser
210 * details to parse new line */
211 state->ts_current_line_lf_seen = 0;
212 if (state->ts_current_line_db == 1) {
213 state->ts_current_line_db = 0;
214 SCFree(state->ts_db);
215 state->ts_db = NULL;
4a6908d3 216 state->ts_db_len = 0;
88115902 217 state->current_line = NULL;
4a6908d3 218 state->current_line_len = 0;
88115902 219 }
576ec7da 220 }
576ec7da 221
88115902 222 uint8_t *lf_idx = memchr(state->input, 0x0a, state->input_len);
576ec7da 223
88115902 224 if (lf_idx == NULL) {
5311cd48
AS
225 /* fragmented lines. Decoder event for special cases. Not all
226 * fragmented lines should be treated as a possible evasion
227 * attempt. With multi payload smtp chunks we can have valid
228 * cases of fragmentation. But within the same segment chunk
229 * if we see fragmentation then it's definitely something you
230 * should alert about */
88115902 231 if (state->ts_current_line_db == 0) {
88115902
AS
232 state->ts_db = SCMalloc(state->input_len);
233 if (state->ts_db == NULL) {
234 return -1;
235 }
4a6908d3 236 state->ts_current_line_db = 1;
88115902
AS
237 memcpy(state->ts_db, state->input, state->input_len);
238 state->ts_db_len = state->input_len;
239 } else {
240 state->ts_db = SCRealloc(state->ts_db, (state->ts_db_len +
241 state->input_len));
242 if (state->ts_db == NULL) {
243 return -1;
244 }
245 memcpy(state->ts_db + state->ts_db_len,
246 state->input, state->input_len);
247 state->ts_db_len += state->input_len;
248 } /* else */
249 state->input += state->input_len;
250 state->input_len = 0;
251
252 return -1;
4a6908d3 253
576ec7da 254 } else {
88115902
AS
255 state->ts_current_line_lf_seen = 1;
256
4a6908d3
AS
257 if (state->ts_current_line_db == 1) {
258 state->ts_db = SCRealloc(state->ts_db,
259 (state->ts_db_len +
260 (lf_idx + 1 - state->input)));
261 if (state->ts_db == NULL) {
262 return -1;
263 }
264 memcpy(state->ts_db + state->ts_db_len,
265 state->input, (lf_idx + 1 - state->input));
266 state->ts_db_len += (lf_idx + 1 - state->input);
267
268 if (state->ts_db_len > 1 &&
269 state->ts_db[state->ts_db_len - 2] == 0x0D) {
270 state->ts_db_len -= 2;
271 state->current_line_delimiter_len = 2;
88115902 272 } else {
4a6908d3
AS
273 state->ts_db_len -= 1;
274 state->current_line_delimiter_len = 1;
88115902 275 }
576ec7da 276
4a6908d3
AS
277 state->current_line = state->ts_db;
278 state->current_line_len = state->ts_db_len;
279
88115902 280 } else {
4a6908d3
AS
281 state->current_line = state->input;
282 state->current_line_len = lf_idx - state->input;
283
284 if (state->input != lf_idx &&
285 *(lf_idx - 1) == 0x0D) {
286 state->current_line_len--;
287 state->current_line_delimiter_len = 2;
88115902 288 } else {
4a6908d3 289 state->current_line_delimiter_len = 1;
88115902 290 }
4a6908d3 291 }
88115902
AS
292
293 state->input_len -= (lf_idx - state->input) + 1;
4a6908d3 294 state->input = (lf_idx + 1);
88115902
AS
295
296 return 0;
4a6908d3 297 }
88115902
AS
298
299 /* toclient */
576ec7da 300 } else {
88115902
AS
301 if (state->tc_current_line_lf_seen == 1) {
302 /* we have seen the lf for the previous line. Clear the parser
303 * details to parse new line */
304 state->tc_current_line_lf_seen = 0;
305 if (state->tc_current_line_db == 1) {
306 state->tc_current_line_db = 0;
307 SCFree(state->tc_db);
308 state->tc_db = NULL;
4a6908d3 309 state->tc_db_len = 0;
88115902 310 state->current_line = NULL;
4a6908d3 311 state->current_line_len = 0;
88115902
AS
312 }
313 }
314
315 uint8_t *lf_idx = memchr(state->input, 0x0a, state->input_len);
316
317 if (lf_idx == NULL) {
5311cd48
AS
318 /* fragmented lines. Decoder event for special cases. Not all
319 * fragmented lines should be treated as a possible evasion
320 * attempt. With multi payload smtp chunks we can have valid
321 * cases of fragmentation. But within the same segment chunk
322 * if we see fragmentation then it's definitely something you
323 * should alert about */
88115902 324 if (state->tc_current_line_db == 0) {
88115902
AS
325 state->tc_db = SCMalloc(state->input_len);
326 if (state->tc_db == NULL) {
576ec7da
AS
327 return -1;
328 }
4a6908d3 329 state->tc_current_line_db = 1;
88115902
AS
330 memcpy(state->tc_db, state->input, state->input_len);
331 state->tc_db_len = state->input_len;
576ec7da 332 } else {
88115902
AS
333 state->tc_db = SCRealloc(state->tc_db, (state->tc_db_len +
334 state->input_len));
335 if (state->tc_db == NULL) {
336 return -1;
337 }
338 memcpy(state->tc_db + state->tc_db_len,
339 state->input, state->input_len);
340 state->tc_db_len += state->input_len;
341 } /* else */
342 state->input += state->input_len;
343 state->input_len = 0;
576ec7da 344
88115902 345 return -1;
4a6908d3 346
576ec7da 347 } else {
88115902
AS
348 state->tc_current_line_lf_seen = 1;
349
4a6908d3
AS
350 if (state->tc_current_line_db == 1) {
351 state->tc_db = SCRealloc(state->tc_db,
352 (state->tc_db_len +
353 (lf_idx + 1 - state->input)));
354 if (state->tc_db == NULL) {
355 return -1;
356 }
357 memcpy(state->tc_db + state->tc_db_len,
358 state->input, (lf_idx + 1 - state->input));
359 state->tc_db_len += (lf_idx + 1 - state->input);
360
361 if (state->tc_db_len > 1 &&
362 state->tc_db[state->tc_db_len - 2] == 0x0D) {
363 state->tc_db_len -= 2;
364 state->current_line_delimiter_len = 2;
88115902 365 } else {
4a6908d3
AS
366 state->tc_db_len -= 1;
367 state->current_line_delimiter_len = 1;
576ec7da 368 }
88115902 369
4a6908d3
AS
370 state->current_line = state->tc_db;
371 state->current_line_len = state->tc_db_len;
372
576ec7da 373 } else {
4a6908d3
AS
374 state->current_line = state->input;
375 state->current_line_len = lf_idx - state->input;
376
377 if (state->input != lf_idx &&
378 *(lf_idx - 1) == 0x0D) {
379 state->current_line_len--;
380 state->current_line_delimiter_len = 2;
88115902 381 } else {
4a6908d3 382 state->current_line_delimiter_len = 1;
88115902 383 }
4a6908d3 384 }
576ec7da 385
88115902 386 state->input_len -= (lf_idx - state->input) + 1;
4a6908d3 387 state->input = (lf_idx + 1);
88115902
AS
388
389 return 0;
390 } /* else - if (lf_idx == NULL) */
391 }
576ec7da 392
576ec7da
AS
393}
394
5311cd48 395static int SMTPInsertCommandIntoCommandBuffer(uint8_t command, SMTPState *state, Flow *f)
576ec7da 396{
7b0f261f
VJ
397 SCEnter();
398
576ec7da 399 if (state->cmds_cnt >= state->cmds_buffer_len) {
bc5c9f4a
VJ
400 int increment = SMTP_COMMAND_BUFFER_STEPS;
401 if ((int)(state->cmds_buffer_len + SMTP_COMMAND_BUFFER_STEPS) > (int)USHRT_MAX) {
402 increment = USHRT_MAX - state->cmds_buffer_len;
403 }
404
576ec7da
AS
405 state->cmds = SCRealloc(state->cmds,
406 sizeof(uint8_t) *
407 (state->cmds_buffer_len +
bc5c9f4a 408 increment));
576ec7da 409 if (state->cmds == NULL) {
7b0f261f 410 SCLogDebug("SCRalloc failure");
576ec7da
AS
411 return -1;
412 }
bc5c9f4a 413 state->cmds_buffer_len += increment;
576ec7da
AS
414 }
415 if (state->cmds_cnt >= 1 &&
416 ((state->cmds[state->cmds_cnt - 1] == SMTP_COMMAND_STARTTLS) ||
417 (state->cmds[state->cmds_cnt - 1] == SMTP_COMMAND_DATA))) {
418 /* decoder event */
5311cd48
AS
419 AppLayerDecoderEventsSetEvent(f,
420 SMTP_DECODER_EVENT_INVALID_PIPELINED_SEQUENCE);
576ec7da
AS
421 /* we have to have EHLO, DATA, VRFY, EXPN, TURN, QUIT, NOOP,
422 * STARTTLS as the last command in pipelined mode */
423 }
bc5c9f4a
VJ
424
425 /** \todo decoder event */
7b0f261f
VJ
426 if ((int)(state->cmds_cnt + 1) > (int)USHRT_MAX) {
427 SCLogDebug("command buffer overflow");
bc5c9f4a 428 return -1;
7b0f261f 429 }
bc5c9f4a 430
576ec7da
AS
431 state->cmds[state->cmds_cnt] = command;
432 state->cmds_cnt++;
433
434 return 0;
435}
436
d3ca65de
AS
437static int SMTPProcessCommandBDAT(SMTPState *state, Flow *f,
438 AppLayerParserState *pstate)
439{
7b0f261f
VJ
440 SCEnter();
441
d3ca65de
AS
442 state->bdat_chunk_idx += (state->current_line_len +
443 state->current_line_delimiter_len);
444 if (state->bdat_chunk_idx > state->bdat_chunk_len) {
445 state->parser_state &= ~SMTP_PARSER_STATE_COMMAND_DATA_MODE;
446 /* decoder event */
5311cd48
AS
447 AppLayerDecoderEventsSetEvent(f,
448 SMTP_DECODER_EVENT_BDAT_CHUNK_LEN_EXCEEDED);
7b0f261f 449 SCReturnInt(-1);
d3ca65de
AS
450 } else if (state->bdat_chunk_idx == state->bdat_chunk_len) {
451 state->parser_state &= ~SMTP_PARSER_STATE_COMMAND_DATA_MODE;
452 }
453
7b0f261f 454 SCReturnInt(0);
d3ca65de
AS
455}
456
576ec7da 457static int SMTPProcessCommandDATA(SMTPState *state, Flow *f,
5311cd48 458 AppLayerParserState *pstate)
576ec7da 459{
7b0f261f
VJ
460 SCEnter();
461
576ec7da
AS
462 if (!(state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
463 /* looks like are still waiting for a confirmination from the server */
464 return 0;
465 }
466
467 if (state->current_line_len == 1 && state->current_line[0] == '.') {
468 state->parser_state &= ~SMTP_PARSER_STATE_COMMAND_DATA_MODE;
469 /* kinda like a hack. The mail sent in DATA mode, would be
470 * acknowledged with a reply. We insert a dummy command to
471 * the command buffer to be used by the reply handler to match
472 * the reply received */
5311cd48 473 SMTPInsertCommandIntoCommandBuffer(SMTP_COMMAND_DATA_MODE, state, f);
576ec7da
AS
474 }
475
476 return 0;
477}
478
479static int SMTPProcessCommandSTARTTLS(SMTPState *state, Flow *f,
480 AppLayerParserState *pstate)
481{
482 return 0;
483}
484
485static int SMTPProcessReply(SMTPState *state, Flow *f,
486 AppLayerParserState *pstate)
487{
7b0f261f
VJ
488 SCEnter();
489
576ec7da 490 uint64_t reply_code = 0;
997eaf42 491 PatternMatcherQueue *pmq = state->thread_local_data;
576ec7da 492
576ec7da
AS
493 /* the reply code has to contain at least 3 bytes, to hold the 3 digit
494 * reply code */
495 if (state->current_line_len < 3) {
496 /* decoder event */
5311cd48
AS
497 AppLayerDecoderEventsSetEvent(f,
498 SMTP_DECODER_EVENT_INVALID_REPLY);
576ec7da
AS
499 return -1;
500 }
501
502 if (state->current_line_len >= 4) {
503 if (state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY) {
504 if (state->current_line[3] != '-') {
505 state->parser_state &= ~SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY;
506 }
507 } else {
508 if (state->current_line[3] == '-') {
509 state->parser_state |= SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY;
510 }
511 }
512 } else {
513 if (state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY) {
514 state->parser_state &= ~SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY;
515 }
516 }
517
4d38a571
AS
518 /* I don't like this pmq reset here. We'll devise a method later, that
519 * should make the use of the mpm very efficient */
997eaf42 520 PmqReset(pmq);
4d38a571 521 int mpm_cnt = mpm_table[SMTP_MPM].Search(smtp_mpm_ctx, smtp_mpm_thread_ctx,
997eaf42 522 pmq, state->current_line,
4d38a571
AS
523 3);
524 if (mpm_cnt == 0) {
525 /* set decoder event - reply code invalid */
5311cd48
AS
526 AppLayerDecoderEventsSetEvent(f,
527 SMTP_DECODER_EVENT_INVALID_REPLY);
7b0f261f
VJ
528 SCLogDebug("invalid reply code %02x %02x %02x",
529 state->current_line[0], state->current_line[1], state->current_line[2]);
530 SCReturnInt(-1);
4d38a571 531 }
997eaf42 532 reply_code = smtp_reply_map[pmq->pattern_id_array[0]].enum_value;
4d38a571
AS
533
534 if (state->cmds_idx == state->cmds_cnt) {
0d7159b5
AS
535 if (!(state->parser_state & SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
536 state->parser_state |= SMTP_PARSER_STATE_FIRST_REPLY_SEEN;
537 if (reply_code == SMTP_REPLY_220)
538 SCReturnInt(0);
539 else
540 AppLayerDecoderEventsSetEvent(f, SMTP_DECODER_EVENT_INVALID_REPLY);
4d38a571 541 } else {
0d7159b5
AS
542 /* decoder event - unable to match reply with request */
543 SCLogDebug("unable to match reply with request");
544 SCReturnInt(-1);
576ec7da
AS
545 }
546 }
547
548 if (state->cmds[state->cmds_idx] == SMTP_COMMAND_STARTTLS) {
4d38a571 549 if (reply_code == SMTP_REPLY_220) {
576ec7da
AS
550 /* we are entering STARRTTLS data mode */
551 state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE;
552 pstate->flags |= APP_LAYER_PARSER_DONE;
553 pstate->flags |= APP_LAYER_PARSER_NO_INSPECTION;
554 pstate->flags |= APP_LAYER_PARSER_NO_REASSEMBLY;
555 } else {
556 /* decoder event */
5311cd48
AS
557 AppLayerDecoderEventsSetEvent(f,
558 SMTP_DECODER_EVENT_TLS_REJECTED);
576ec7da
AS
559 }
560 } else if (state->cmds[state->cmds_idx] == SMTP_COMMAND_DATA) {
4d38a571 561 if (reply_code == SMTP_REPLY_354) {
576ec7da
AS
562 /* Next comes the mail for the DATA command in toserver direction */
563 state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE;
564 } else {
565 /* decoder event */
5311cd48
AS
566 AppLayerDecoderEventsSetEvent(f,
567 SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED);
576ec7da
AS
568 }
569 } else {
4d38a571
AS
570 /* we don't care for any other command for now */
571 /* check if reply falls in the valid list of replies for SMTP. If not
572 * decoder event */
576ec7da
AS
573 }
574
4d38a571 575 /* if it is a multi-line reply, we need to move the index only once for all
576ec7da
AS
576 * the line of the reply. We unset the multiline flag on the last
577 * line of the multiline reply, following which we increment the index */
578 if (!(state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY)) {
579 state->cmds_idx++;
580 }
581
582 /* if we have matched all the buffered commands, reset the cnt and index */
583 if (state->cmds_idx == state->cmds_cnt) {
584 state->cmds_cnt = 0;
585 state->cmds_idx = 0;
586 }
587
588 return 0;
589}
590
d3ca65de
AS
591static int SMTPParseCommandBDAT(SMTPState *state)
592{
7b0f261f
VJ
593 SCEnter();
594
d3ca65de
AS
595 int i = 4;
596 while (i < state->current_line_len) {
597 if (state->current_line[i] != ' ') {
598 break;
599 }
600 i++;
601 }
602 if (i == 4) {
603 /* decoder event */
604 return -1;
605 }
606 if (i == state->current_line_len) {
607 /* decoder event */
608 return -1;
609 }
610 uint8_t *endptr = NULL;
611 state->bdat_chunk_len = strtoul((const char *)state->current_line + i,
612 (char **)&endptr, 10);
613 if (endptr == state->current_line + i) {
614 /* decoder event */
615 return -1;
616 }
617
618 return 0;
619}
620
576ec7da
AS
621static int SMTPProcessRequest(SMTPState *state, Flow *f,
622 AppLayerParserState *pstate)
623{
7b0f261f
VJ
624 SCEnter();
625
0d7159b5
AS
626 if (!(state->parser_state & SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
627 AppLayerDecoderEventsSetEvent(f, SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE);
628 }
629
576ec7da
AS
630 /* there are 2 commands that can push it into this COMMAND_DATA mode -
631 * STARTTLS and DATA */
632 if (!(state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
d3ca65de
AS
633 int r = 0;
634
576ec7da
AS
635 if (state->current_line_len >= 8 &&
636 SCMemcmpLowercase("starttls", state->current_line, 8) == 0) {
637 state->current_command = SMTP_COMMAND_STARTTLS;
638 } else if (state->current_line_len >= 4 &&
639 SCMemcmpLowercase("data", state->current_line, 4) == 0) {
640 state->current_command = SMTP_COMMAND_DATA;
d3ca65de
AS
641 } else if (state->current_line_len >= 4 &&
642 SCMemcmpLowercase("bdat", state->current_line, 4) == 0) {
643 r = SMTPParseCommandBDAT(state);
7b0f261f
VJ
644 if (r == -1) {
645 SCReturnInt(-1);
646 }
d3ca65de
AS
647 state->current_command = SMTP_COMMAND_BDAT;
648 state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE;
576ec7da
AS
649 } else {
650 state->current_command = SMTP_COMMAND_OTHER_CMD;
651 }
652
653 /* Every command is inserted into a command buffer, to be matched
654 * against reply(ies) sent by the server */
655 if (SMTPInsertCommandIntoCommandBuffer(state->current_command,
5311cd48 656 state, f) == -1) {
7b0f261f 657 SCReturnInt(-1);
576ec7da 658 }
d3ca65de 659
7b0f261f 660 SCReturnInt(r);
576ec7da
AS
661 }
662
663 switch (state->current_command) {
664 case SMTP_COMMAND_STARTTLS:
665 return SMTPProcessCommandSTARTTLS(state, f, pstate);
666
667 case SMTP_COMMAND_DATA:
668 return SMTPProcessCommandDATA(state, f, pstate);
669
d3ca65de
AS
670 case SMTP_COMMAND_BDAT:
671 return SMTPProcessCommandBDAT(state, f, pstate);
672
576ec7da
AS
673 default:
674 /* we have nothing to do with any other command at this instant.
675 * Just let it go through */
7b0f261f 676 SCReturnInt(0);
576ec7da
AS
677 }
678}
679
88115902
AS
680static int SMTPParse(int direction, Flow *f, SMTPState *state,
681 AppLayerParserState *pstate, uint8_t *input,
997eaf42
AS
682 uint32_t input_len,
683 PatternMatcherQueue *local_data, AppLayerParserResult *output)
576ec7da 684{
7b0f261f
VJ
685 SCEnter();
686
576ec7da
AS
687 state->input = input;
688 state->input_len = input_len;
88115902 689 state->direction = direction;
997eaf42 690 state->thread_local_data = local_data;
576ec7da 691
87599bc7
AS
692 /* toserver */
693 if (direction == 0) {
694 while (SMTPGetLine(state) >= 0) {
d3ca65de 695 if (SMTPProcessRequest(state, f, pstate) == -1)
7b0f261f 696 SCReturnInt(-1);
87599bc7 697 }
88115902 698
87599bc7
AS
699 /* toclient */
700 } else {
701 while (SMTPGetLine(state) >= 0) {
d3ca65de 702 if (SMTPProcessReply(state, f, pstate) == -1)
7b0f261f 703 SCReturnInt(-1);
88115902 704 }
576ec7da
AS
705 }
706
7b0f261f 707 SCReturnInt(0);
576ec7da
AS
708}
709
88115902 710static int SMTPParseClientRecord(Flow *f, void *alstate,
576ec7da
AS
711 AppLayerParserState *pstate,
712 uint8_t *input, uint32_t input_len,
9a6aef45 713 void *local_data, AppLayerParserResult *output)
576ec7da 714{
7b0f261f
VJ
715 SCEnter();
716
88115902 717 /* first arg 0 is toserver */
997eaf42
AS
718 return SMTPParse(0, f, alstate, pstate, input, input_len, local_data,
719 output);
88115902 720}
576ec7da 721
88115902
AS
722static int SMTPParseServerRecord(Flow *f, void *alstate,
723 AppLayerParserState *pstate,
724 uint8_t *input, uint32_t input_len,
9a6aef45 725 void *local_data, AppLayerParserResult *output)
88115902 726{
7b0f261f
VJ
727 SCEnter();
728
88115902 729 /* first arg 1 is toclient */
997eaf42
AS
730 return SMTPParse(1, f, alstate, pstate, input, input_len, local_data,
731 output);
576ec7da
AS
732
733 return 0;
734}
735
736/**
737 * \internal
738 * \brief Function to allocate SMTP state memory.
739 */
740static void *SMTPStateAlloc(void)
741{
742 SMTPState *smtp_state = SCMalloc(sizeof(SMTPState));
e176be6f 743 if (unlikely(smtp_state == NULL))
576ec7da
AS
744 return NULL;
745 memset(smtp_state, 0, sizeof(SMTPState));
746
747 smtp_state->cmds = SCMalloc(sizeof(uint8_t) *
748 SMTP_COMMAND_BUFFER_STEPS);
749 if (smtp_state->cmds == NULL) {
750 SCFree(smtp_state);
751 return NULL;
752 }
753 smtp_state->cmds_buffer_len = SMTP_COMMAND_BUFFER_STEPS;
754
997eaf42
AS
755 return smtp_state;
756}
757
758static void *SMTPLocalStorageAlloc(void)
759{
760 /* needed by the mpm */
761 PatternMatcherQueue *pmq = SCMalloc(sizeof(PatternMatcherQueue));
e176be6f 762 if (unlikely(pmq == NULL)) {
4d38a571
AS
763 exit(EXIT_FAILURE);
764 }
997eaf42 765 PmqSetup(pmq, 0,
4d38a571
AS
766 sizeof(smtp_reply_map)/sizeof(SCEnumCharMap) - 2);
767
997eaf42
AS
768 return pmq;
769}
770
771static void SMTPLocalStorageFree(void *pmq)
772{
773 if (pmq != NULL) {
774 PmqFree(pmq);
775 SCFree(pmq);
776 }
777
778 return;
576ec7da
AS
779}
780
781/**
782 * \internal
783 * \brief Function to free SMTP state memory.
784 */
785static void SMTPStateFree(void *p)
786{
787 SMTPState *smtp_state = (SMTPState *)p;
788
789 if (smtp_state->cmds != NULL) {
790 SCFree(smtp_state->cmds);
791 }
88115902
AS
792 if (smtp_state->ts_current_line_db) {
793 SCFree(smtp_state->ts_db);
794 }
795 if (smtp_state->tc_current_line_db) {
796 SCFree(smtp_state->tc_db);
797 }
576ec7da
AS
798
799 SCFree(smtp_state);
800
801 return;
802}
803
4d38a571
AS
804static void SMTPSetMpmState(void)
805{
806 smtp_mpm_ctx = SCMalloc(sizeof(MpmCtx));
e176be6f 807 if (unlikely(smtp_mpm_ctx == NULL)) {
4d38a571
AS
808 exit(EXIT_FAILURE);
809 }
810 memset(smtp_mpm_ctx, 0, sizeof(MpmCtx));
811
812 smtp_mpm_thread_ctx = SCMalloc(sizeof(MpmThreadCtx));
e176be6f 813 if (unlikely(smtp_mpm_thread_ctx == NULL)) {
4d38a571
AS
814 exit(EXIT_FAILURE);
815 }
816 memset(smtp_mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
817
3c2ddf04 818 mpm_table[SMTP_MPM].InitCtx(smtp_mpm_ctx);
4d38a571
AS
819 mpm_table[SMTP_MPM].InitThreadCtx(smtp_mpm_ctx, smtp_mpm_thread_ctx, 0);
820
821 uint32_t i = 0;
822 for (i = 0; i < sizeof(smtp_reply_map)/sizeof(SCEnumCharMap) - 1; i++) {
823 SCEnumCharMap *map = &smtp_reply_map[i];
824 mpm_table[SMTP_MPM].AddPatternNocase(smtp_mpm_ctx,
825 (uint8_t *)map->enum_name,
826 3 /* reply codes always 3 bytes */,
827 0 /* now defunct option */,
828 0 /* now defunct option */,
829 i /* pattern id */,
830 0 /* no sid */,
831 0 /* no flags */);
832 }
833
834 mpm_table[SMTP_MPM].Prepare(smtp_mpm_ctx);
835}
836
576ec7da
AS
837/**
838 * \brief Register the SMPT Protocol parser.
839 */
840void RegisterSMTPParsers(void)
841{
10966245
AS
842 char *proto_name = "smtp";
843
ddde572f
AS
844 if (AppLayerProtoDetectionEnabled(proto_name)) {
845 AlpProtoAdd(&alp_proto_ctx, proto_name, IPPROTO_TCP, ALPROTO_SMTP, "EHLO", 4, 0,
846 STREAM_TOSERVER);
847 AlpProtoAdd(&alp_proto_ctx, proto_name, IPPROTO_TCP, ALPROTO_SMTP, "HELO", 4, 0,
848 STREAM_TOSERVER);
0d7159b5
AS
849 AlpProtoAdd(&alp_proto_ctx, proto_name, IPPROTO_TCP, ALPROTO_SMTP, "QUIT", 4, 0,
850 STREAM_TOSERVER);
851 AppLayerRegisterParserAcceptableDataDirection(ALPROTO_SMTP, STREAM_TOCLIENT);
ddde572f
AS
852 } else {
853 SCLogInfo("Protocol detection and parser disabled for %s protocol.",
854 proto_name);
855 return;
856 }
576ec7da 857
ddde572f
AS
858 if (AppLayerParserEnabled(proto_name)) {
859 AppLayerRegisterStateFuncs(ALPROTO_SMTP, SMTPStateAlloc, SMTPStateFree);
576ec7da 860
ddde572f
AS
861 AppLayerRegisterProto(proto_name, ALPROTO_SMTP, STREAM_TOSERVER,
862 SMTPParseClientRecord);
863 AppLayerRegisterProto(proto_name, ALPROTO_SMTP, STREAM_TOCLIENT,
864 SMTPParseServerRecord);
6cb00142
AS
865
866 AppLayerRegisterEventsTable(ALPROTO_SMTP, smtp_decoder_event_table);
576ec7da 867
ddde572f
AS
868 AppLayerRegisterLocalStorageFunc(ALPROTO_SMTP, SMTPLocalStorageAlloc,
869 SMTPLocalStorageFree);
870 } else {
871 SCLogInfo("Parsed disabled for %s protocol. Protocol detection"
872 "still on.", proto_name);
873 }
997eaf42 874
4d38a571
AS
875 SMTPSetMpmState();
876
9faa4b74 877#ifdef UNITTESTS
0d7159b5 878 AppLayerParserRegisterUnittests(ALPROTO_SMTP, SMTPParserRegisterTests);
9faa4b74 879#endif
576ec7da
AS
880 return;
881}
882
883/***************************************Unittests******************************/
884
87599bc7
AS
885#ifdef UNITTESTS
886
576ec7da
AS
887/*
888 * \test Test STARTTLS.
889 */
890int SMTPParserTest01(void)
891{
892 int result = 0;
893 Flow f;
894 int r = 0;
895
896 /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
897 uint8_t welcome_reply[] = {
898 0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
899 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
900 0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
901 0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
902 0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
903 0x0d, 0x0a
904 };
905 uint32_t welcome_reply_len = sizeof(welcome_reply);
906
907 /* EHLO [192.168.0.158]<CR><LF> */
908 uint8_t request1[] = {
909 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x5b, 0x31, 0x39,
910 0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e,
911 0x31, 0x35, 0x38, 0x5d, 0x0d, 0x0a
912 };
913 uint32_t request1_len = sizeof(request1);
914 /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
915 * 250-SIZE 35882577<CR><LF>
916 * 250-8BITMIME<CR><LF>
917 * 250-STARTTLS<CR><LF>
918 * 250 ENHANCEDSTATUSCODES<CR><LF>
919 */
920 uint8_t reply1[] = {
921 0x32, 0x35, 0x30, 0x2d, 0x6d, 0x78, 0x2e, 0x67,
922 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
923 0x6d, 0x20, 0x61, 0x74, 0x20, 0x79, 0x6f, 0x75,
924 0x72, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
925 0x65, 0x2c, 0x20, 0x5b, 0x31, 0x31, 0x37, 0x2e,
926 0x31, 0x39, 0x38, 0x2e, 0x31, 0x31, 0x35, 0x2e,
927 0x35, 0x30, 0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30,
928 0x2d, 0x53, 0x49, 0x5a, 0x45, 0x20, 0x33, 0x35,
929 0x38, 0x38, 0x32, 0x35, 0x37, 0x37, 0x0d, 0x0a,
930 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49, 0x54,
931 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35,
932 0x30, 0x2d, 0x53, 0x54, 0x41, 0x52, 0x54, 0x54,
933 0x4c, 0x53, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20,
934 0x45, 0x4e, 0x48, 0x41, 0x4e, 0x43, 0x45, 0x44,
935 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x43, 0x4f,
936 0x44, 0x45, 0x53, 0x0d, 0x0a
937 };
938 uint32_t reply1_len = sizeof(reply1);
939
940 /* STARTTLS<CR><LF> */
941 uint8_t request2[] = {
942 0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
943 0x0d, 0x0a
944 };
945 uint32_t request2_len = sizeof(request2);
946 /* 220 2.0.0 Ready to start TLS<CR><LF> */
947 uint8_t reply2[] = {
948 0x32, 0x32, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
949 0x30, 0x20, 0x52, 0x65, 0x61, 0x64, 0x79, 0x20,
950 0x74, 0x6f, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74,
951 0x20, 0x54, 0x4c, 0x53, 0x0d, 0x0a
952 };
953 uint32_t reply2_len = sizeof(reply2);
954
955 TcpSession ssn;
956
957 memset(&f, 0, sizeof(f));
958 memset(&ssn, 0, sizeof(ssn));
959
960 FLOW_INITIALIZE(&f);
961 f.protoctx = (void *)&ssn;
962
963 StreamTcpInitConfig(TRUE);
997eaf42 964 void *thread_local_data = SMTPLocalStorageAlloc();
576ec7da 965
cd3e32ce 966 SCMutexLock(&f.m);
0d7159b5
AS
967 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
968 welcome_reply, welcome_reply_len);
576ec7da
AS
969 if (r != 0) {
970 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 971 SCMutexUnlock(&f.m);
576ec7da
AS
972 goto end;
973 }
cd3e32ce 974 SCMutexUnlock(&f.m);
06904c90 975 SMTPState *smtp_state = f.alstate;
576ec7da
AS
976 if (smtp_state == NULL) {
977 printf("no smtp state: ");
978 goto end;
979 }
980 if (smtp_state->input_len != 0 ||
0d7159b5 981 smtp_state->cmds_cnt != 0 ||
576ec7da 982 smtp_state->cmds_idx != 0 ||
0d7159b5 983 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
576ec7da
AS
984 printf("smtp parser in inconsistent state\n");
985 goto end;
986 }
987
cd3e32ce 988 SCMutexLock(&f.m);
0d7159b5
AS
989 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
990 request1, request1_len);
576ec7da
AS
991 if (r != 0) {
992 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 993 SCMutexUnlock(&f.m);
576ec7da
AS
994 goto end;
995 }
cd3e32ce 996 SCMutexUnlock(&f.m);
576ec7da 997 if (smtp_state->input_len != 0 ||
576ec7da
AS
998 smtp_state->cmds_cnt != 1 ||
999 smtp_state->cmds_idx != 0 ||
1000 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1001 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1002 printf("smtp parser in inconsistent state\n");
1003 goto end;
1004 }
1005
cd3e32ce 1006 SCMutexLock(&f.m);
997eaf42 1007 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
576ec7da
AS
1008 reply1, reply1_len);
1009 if (r != 0) {
1010 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1011 SCMutexUnlock(&f.m);
576ec7da
AS
1012 goto end;
1013 }
cd3e32ce 1014 SCMutexUnlock(&f.m);
576ec7da 1015 if (smtp_state->input_len != 0 ||
576ec7da
AS
1016 smtp_state->cmds_cnt != 0 ||
1017 smtp_state->cmds_idx != 0 ||
1018 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1019 printf("smtp parser in inconsistent state\n");
1020 goto end;
1021 }
1022
cd3e32ce 1023 SCMutexLock(&f.m);
997eaf42 1024 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
576ec7da
AS
1025 request2, request2_len);
1026 if (r != 0) {
1027 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1028 SCMutexUnlock(&f.m);
576ec7da
AS
1029 goto end;
1030 }
cd3e32ce 1031 SCMutexUnlock(&f.m);
576ec7da 1032 if (smtp_state->input_len != 0 ||
576ec7da
AS
1033 smtp_state->cmds_cnt != 1 ||
1034 smtp_state->cmds_idx != 0 ||
1035 smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS ||
1036 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1037 printf("smtp parser in inconsistent state\n");
1038 goto end;
1039 }
1040
cd3e32ce 1041 SCMutexLock(&f.m);
997eaf42 1042 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
576ec7da
AS
1043 reply2, reply2_len);
1044 if (r != 0) {
1045 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1046 SCMutexUnlock(&f.m);
576ec7da
AS
1047 goto end;
1048 }
cd3e32ce 1049 SCMutexUnlock(&f.m);
576ec7da 1050 if (smtp_state->input_len != 0 ||
576ec7da
AS
1051 smtp_state->cmds_cnt != 0 ||
1052 smtp_state->cmds_idx != 0 ||
1053 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
1054 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1055 printf("smtp parser in inconsistent state\n");
1056 goto end;
1057 }
1058
1059 if (!(f.flags & FLOW_NOPAYLOAD_INSPECTION) ||
1060 !(f.flags & FLOW_NO_APPLAYER_INSPECTION) ||
1061 !(((TcpSession *)f.protoctx)->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) ||
1062 !(((TcpSession *)f.protoctx)->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
1063 goto end;
1064 }
1065
1066 result = 1;
1067end:
576ec7da
AS
1068 StreamTcpFreeConfig(TRUE);
1069 FLOW_DESTROY(&f);
997eaf42 1070 SMTPLocalStorageFree(thread_local_data);
576ec7da
AS
1071 return result;
1072}
1073
1074/**
1075 * \test Test multiple DATA commands(full mail transactions).
1076 */
1077int SMTPParserTest02(void)
1078{
1079 int result = 0;
1080 Flow f;
1081 int r = 0;
1082
1083 /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
1084 uint8_t welcome_reply[] = {
1085 0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
1086 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
1087 0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
1088 0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
1089 0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
1090 0x0d, 0x0a
1091 };
1092 uint32_t welcome_reply_len = sizeof(welcome_reply);
1093
1094 /* EHLO boo.com<CR><LF> */
1095 uint8_t request1[] = {
1096 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
1097 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
1098 };
1099 uint32_t request1_len = sizeof(request1);
1100 /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
1101 * 250-SIZE 35882577<CR><LF>
1102 * 250-8BITMIME<CR><LF>
1103 * 250-STARTTLS<CR><LF>
1104 * 250 ENHANCEDSTATUSCODES<CR><LF>
1105 */
1106 uint8_t reply1[] = {
1107 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
1108 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
1109 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
1110 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
1111 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
1112 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
1113 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
1114 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
1115 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
1116 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
1117 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
1118 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
1119 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
1120 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
1121 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
1122 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
1123 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
1124 };
1125 uint32_t reply1_len = sizeof(reply1);
1126
1127 /* MAIL FROM:asdff@asdf.com<CR><LF> */
1128 uint8_t request2[] = {
1129 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
1130 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
1131 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
1132 0x0d, 0x0a
1133 };
1134 uint32_t request2_len = sizeof(request2);
1135 /* 250 2.1.0 Ok<CR><LF> */
1136 uint8_t reply2[] = {
1137 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
1138 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
1139 };
1140 uint32_t reply2_len = sizeof(reply2);
1141
1142 /* RCPT TO:bimbs@gmail.com<CR><LF> */
1143 uint8_t request3[] = {
1144 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
1145 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
1146 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
1147 0x0a
1148 };
1149 uint32_t request3_len = sizeof(request3);
1150 /* 250 2.1.5 Ok<CR><LF> */
1151 uint8_t reply3[] = {
1152 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
1153 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
1154 };
1155 uint32_t reply3_len = sizeof(reply3);
1156
1157 /* DATA<CR><LF> */
1158 uint8_t request4[] = {
1159 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
1160 };
1161 uint32_t request4_len = sizeof(request4);
1162 /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
1163 uint8_t reply4[] = {
1164 0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
1165 0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
1166 0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
1167 0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
1168 0x4c, 0x46, 0x3e, 0x0d, 0x0a
1169 };
1170 uint32_t reply4_len = sizeof(reply4);
1171
1172 /* FROM:asdff@asdf.com<CR><LF> */
1173 uint8_t request5_1[] = {
1174 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
1175 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
1176 0x63, 0x6f, 0x6d, 0x0d, 0x0a
1177 };
1178 uint32_t request5_1_len = sizeof(request5_1);
1179 /* TO:bimbs@gmail.com<CR><LF> */
1180 uint8_t request5_2[] = {
1181 0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73,
1182 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63,
1183 0x6f, 0x6d, 0x0d, 0x0a
1184 };
1185 uint32_t request5_2_len = sizeof(request5_2);
1186 /* <CR><LF> */
1187 uint8_t request5_3[] = {
1188 0x0d, 0x0a
1189 };
1190 uint32_t request5_3_len = sizeof(request5_3);
1191 /* this is test mail1<CR><LF> */
1192 uint8_t request5_4[] = {
1193 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
1194 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x69,
1195 0x6c, 0x31, 0x0d, 0x0a
1196 };
1197 uint32_t request5_4_len = sizeof(request5_4);
1198 /* .<CR><LF> */
1199 uint8_t request5_5[] = {
1200 0x2e, 0x0d, 0x0a
1201 };
1202 uint32_t request5_5_len = sizeof(request5_5);
1203 /* 250 2.0.0 Ok: queued as 6A1AF20BF2<CR><LF> */
1204 uint8_t reply5[] = {
1205 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
1206 0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
1207 0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
1208 0x36, 0x41, 0x31, 0x41, 0x46, 0x32, 0x30, 0x42,
1209 0x46, 0x32, 0x0d, 0x0a
1210 };
1211 uint32_t reply5_len = sizeof(reply5);
1212
1213 /* MAIL FROM:asdfg@asdf.com<CR><LF> */
1214 uint8_t request6[] = {
1215 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
1216 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x67, 0x40,
1217 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
1218 0x0d, 0x0a
1219 };
1220 uint32_t request6_len = sizeof(request6);
1221 /* 250 2.1.0 Ok<CR><LF> */
1222 uint8_t reply6[] = {
1223 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
1224 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
1225 };
1226 uint32_t reply6_len = sizeof(reply6);
1227
1228 /* RCPT TO:bimbs@gmail.com<CR><LF> */
1229 uint8_t request7[] = {
1230 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
1231 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
1232 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
1233 0x0a
1234 };
1235 uint32_t request7_len = sizeof(request7);
1236 /* 250 2.1.5 Ok<CR><LF> */
1237 uint8_t reply7[] = {
1238 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
1239 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
1240 };
1241 uint32_t reply7_len = sizeof(reply7);
1242
1243 /* DATA<CR><LF> */
1244 uint8_t request8[] = {
1245 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
1246 };
1247 uint32_t request8_len = sizeof(request8);
1248 /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
1249 uint8_t reply8[] = {
1250 0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
1251 0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
1252 0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
1253 0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
1254 0x4c, 0x46, 0x3e, 0x0d, 0x0a
1255 };
1256 uint32_t reply8_len = sizeof(reply8);
1257
1258 /* FROM:asdfg@gmail.com<CR><LF> */
1259 uint8_t request9_1[] = {
1260 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
1261 0x66, 0x67, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c,
1262 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
1263 };
1264 uint32_t request9_1_len = sizeof(request9_1);
1265 /* TO:bimbs@gmail.com<CR><LF> */
1266 uint8_t request9_2[] = {
1267 0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73,
1268 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63,
1269 0x6f, 0x6d, 0x0d, 0x0a
1270 };
1271 uint32_t request9_2_len = sizeof(request9_2);
1272 /* <CR><LF> */
1273 uint8_t request9_3[] = {
1274 0x0d, 0x0a
1275 };
1276 uint32_t request9_3_len = sizeof(request9_3);
1277 /* this is test mail2<CR><LF> */
1278 uint8_t request9_4[] = {
1279 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
1280 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x69,
1281 0x6c, 0x32, 0x0d, 0x0a
1282 };
1283 uint32_t request9_4_len = sizeof(request9_4);
1284 /* .<CR><LF> */
1285 uint8_t request9_5[] = {
1286 0x2e, 0x0d, 0x0a
1287 };
1288 uint32_t request9_5_len = sizeof(request9_5);
1289 /* 250 2.0.0 Ok: queued as 28CFF20BF2<CR><LF> */
1290 uint8_t reply9[] = {
1291 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
1292 0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
1293 0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
1294 0x32, 0x38, 0x43, 0x46, 0x46, 0x32, 0x30, 0x42,
1295 0x46, 0x32, 0x0d, 0x0a
1296 };
1297 uint32_t reply9_len = sizeof(reply9);
1298
1299 /* QUIT<CR><LF> */
1300 uint8_t request10[] = {
1301 0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
1302 };
1303 uint32_t request10_len = sizeof(request10);
1304 /* 221 2.0.0 Bye<CR><LF> */
1305 uint8_t reply10[] = {
1306 0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
1307 0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
1308 };
1309 uint32_t reply10_len = sizeof(reply10);
1310
1311 TcpSession ssn;
1312
1313 memset(&f, 0, sizeof(f));
1314 memset(&ssn, 0, sizeof(ssn));
1315
1316 FLOW_INITIALIZE(&f);
1317 f.protoctx = (void *)&ssn;
1318
1319 StreamTcpInitConfig(TRUE);
997eaf42 1320 void *thread_local_data = SMTPLocalStorageAlloc();
576ec7da 1321
cd3e32ce 1322 SCMutexLock(&f.m);
0d7159b5
AS
1323 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
1324 welcome_reply, welcome_reply_len);
576ec7da
AS
1325 if (r != 0) {
1326 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1327 SCMutexUnlock(&f.m);
576ec7da
AS
1328 goto end;
1329 }
cd3e32ce 1330 SCMutexUnlock(&f.m);
06904c90 1331 SMTPState *smtp_state = f.alstate;
576ec7da
AS
1332 if (smtp_state == NULL) {
1333 printf("no smtp state: ");
1334 goto end;
1335 }
1336 if (smtp_state->input_len != 0 ||
0d7159b5 1337 smtp_state->cmds_cnt != 0 ||
576ec7da 1338 smtp_state->cmds_idx != 0 ||
0d7159b5 1339 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
576ec7da
AS
1340 printf("smtp parser in inconsistent state\n");
1341 goto end;
1342 }
1343
cd3e32ce 1344 SCMutexLock(&f.m);
0d7159b5
AS
1345 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
1346 request1, request1_len);
576ec7da
AS
1347 if (r != 0) {
1348 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1349 SCMutexUnlock(&f.m);
576ec7da
AS
1350 goto end;
1351 }
cd3e32ce 1352 SCMutexUnlock(&f.m);
576ec7da 1353 if (smtp_state->input_len != 0 ||
576ec7da
AS
1354 smtp_state->cmds_cnt != 1 ||
1355 smtp_state->cmds_idx != 0 ||
1356 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1357 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1358 printf("smtp parser in inconsistent state\n");
1359 goto end;
1360 }
1361
cd3e32ce 1362 SCMutexLock(&f.m);
997eaf42 1363 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
576ec7da
AS
1364 reply1, reply1_len);
1365 if (r != 0) {
1366 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1367 SCMutexUnlock(&f.m);
576ec7da
AS
1368 goto end;
1369 }
cd3e32ce 1370 SCMutexUnlock(&f.m);
576ec7da 1371 if (smtp_state->input_len != 0 ||
576ec7da
AS
1372 smtp_state->cmds_cnt != 0 ||
1373 smtp_state->cmds_idx != 0 ||
1374 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1375 printf("smtp parser in inconsistent state\n");
1376 goto end;
1377 }
1378
cd3e32ce 1379 SCMutexLock(&f.m);
997eaf42 1380 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
576ec7da
AS
1381 request2, request2_len);
1382 if (r != 0) {
1383 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1384 SCMutexUnlock(&f.m);
576ec7da
AS
1385 goto end;
1386 }
cd3e32ce 1387 SCMutexUnlock(&f.m);
576ec7da 1388 if (smtp_state->input_len != 0 ||
576ec7da
AS
1389 smtp_state->cmds_cnt != 1 ||
1390 smtp_state->cmds_idx != 0 ||
1391 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1392 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1393 printf("smtp parser in inconsistent state\n");
1394 goto end;
1395 }
1396
cd3e32ce 1397 SCMutexLock(&f.m);
997eaf42 1398 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
576ec7da
AS
1399 reply2, reply2_len);
1400 if (r != 0) {
1401 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1402 SCMutexUnlock(&f.m);
576ec7da
AS
1403 goto end;
1404 }
cd3e32ce 1405 SCMutexUnlock(&f.m);
576ec7da 1406 if (smtp_state->input_len != 0 ||
576ec7da
AS
1407 smtp_state->cmds_cnt != 0 ||
1408 smtp_state->cmds_idx != 0 ||
1409 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
1410 printf("smtp parser in inconsistent state\n");
1411 goto end;
1412 }
1413
cd3e32ce 1414 SCMutexLock(&f.m);
997eaf42 1415 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
576ec7da
AS
1416 request3, request3_len);
1417 if (r != 0) {
1418 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1419 SCMutexUnlock(&f.m);
576ec7da
AS
1420 goto end;
1421 }
cd3e32ce 1422 SCMutexUnlock(&f.m);
576ec7da 1423 if (smtp_state->input_len != 0 ||
576ec7da
AS
1424 smtp_state->cmds_cnt != 1 ||
1425 smtp_state->cmds_idx != 0 ||
1426 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1427 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1428 printf("smtp parser in inconsistent state\n");
1429 goto end;
1430 }
1431
cd3e32ce 1432 SCMutexLock(&f.m);
997eaf42 1433 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
576ec7da
AS
1434 reply3, reply3_len);
1435 if (r != 0) {
1436 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1437 SCMutexUnlock(&f.m);
576ec7da
AS
1438 goto end;
1439 }
cd3e32ce 1440 SCMutexUnlock(&f.m);
576ec7da 1441 if (smtp_state->input_len != 0 ||
576ec7da
AS
1442 smtp_state->cmds_cnt != 0 ||
1443 smtp_state->cmds_idx != 0 ||
1444 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
1445 printf("smtp parser in inconsistent state\n");
1446 goto end;
1447 }
1448
cd3e32ce 1449 SCMutexLock(&f.m);
997eaf42 1450 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
576ec7da
AS
1451 request4, request4_len);
1452 if (r != 0) {
1453 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1454 SCMutexUnlock(&f.m);
576ec7da
AS
1455 goto end;
1456 }
cd3e32ce 1457 SCMutexUnlock(&f.m);
576ec7da 1458 if (smtp_state->input_len != 0 ||
576ec7da
AS
1459 smtp_state->cmds_cnt != 1 ||
1460 smtp_state->cmds_idx != 0 ||
1461 smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
1462 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1463 printf("smtp parser in inconsistent state\n");
1464 goto end;
1465 }
1466
cd3e32ce 1467 SCMutexLock(&f.m);
997eaf42 1468 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
576ec7da
AS
1469 reply4, reply4_len);
1470 if (r != 0) {
1471 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1472 SCMutexUnlock(&f.m);
576ec7da
AS
1473 goto end;
1474 }
cd3e32ce 1475 SCMutexUnlock(&f.m);
576ec7da 1476 if (smtp_state->input_len != 0 ||
576ec7da
AS
1477 smtp_state->cmds_cnt != 0 ||
1478 smtp_state->cmds_idx != 0 ||
1479 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
1480 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1481 printf("smtp parser in inconsistent state\n");
1482 goto end;
1483 }
1484
cd3e32ce 1485 SCMutexLock(&f.m);
997eaf42 1486 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
576ec7da
AS
1487 request5_1, request5_1_len);
1488 if (r != 0) {
1489 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1490 SCMutexUnlock(&f.m);
576ec7da
AS
1491 goto end;
1492 }
cd3e32ce 1493 SCMutexUnlock(&f.m);
576ec7da 1494 if (smtp_state->input_len != 0 ||
576ec7da
AS
1495 smtp_state->cmds_cnt != 0 ||
1496 smtp_state->cmds_idx != 0 ||
1497 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
1498 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1499
1500 printf("smtp parser in inconsistent state\n");
1501 goto end;
1502 }
1503
cd3e32ce 1504 SCMutexLock(&f.m);
997eaf42 1505 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
576ec7da
AS
1506 request5_2, request5_2_len);
1507 if (r != 0) {
1508 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1509 SCMutexUnlock(&f.m);
576ec7da
AS
1510 goto end;
1511 }
cd3e32ce 1512 SCMutexUnlock(&f.m);
576ec7da 1513 if (smtp_state->input_len != 0 ||
576ec7da
AS
1514 smtp_state->cmds_cnt != 0 ||
1515 smtp_state->cmds_idx != 0 ||
1516 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
1517 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1518
1519 printf("smtp parser in inconsistent state\n");
1520 goto end;
1521 }
1522
cd3e32ce 1523 SCMutexLock(&f.m);
997eaf42 1524 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
576ec7da
AS
1525 request5_3, request5_3_len);
1526 if (r != 0) {
1527 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1528 SCMutexUnlock(&f.m);
576ec7da
AS
1529 goto end;
1530 }
cd3e32ce 1531 SCMutexUnlock(&f.m);
576ec7da 1532 if (smtp_state->input_len != 0 ||
576ec7da
AS
1533 smtp_state->cmds_cnt != 0 ||
1534 smtp_state->cmds_idx != 0 ||
1535 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
1536 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1537
1538 printf("smtp parser in inconsistent state\n");
1539 goto end;
1540 }
1541
cd3e32ce 1542 SCMutexLock(&f.m);
997eaf42 1543 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
576ec7da
AS
1544 request5_4, request5_4_len);
1545 if (r != 0) {
1546 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1547 SCMutexUnlock(&f.m);
576ec7da
AS
1548 goto end;
1549 }
cd3e32ce 1550 SCMutexUnlock(&f.m);
576ec7da 1551 if (smtp_state->input_len != 0 ||
576ec7da
AS
1552 smtp_state->cmds_cnt != 0 ||
1553 smtp_state->cmds_idx != 0 ||
1554 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
1555 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1556
1557 printf("smtp parser in inconsistent state\n");
1558 goto end;
1559 }
1560
cd3e32ce 1561 SCMutexLock(&f.m);
997eaf42 1562 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
576ec7da
AS
1563 request5_5, request5_5_len);
1564 if (r != 0) {
1565 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1566 SCMutexUnlock(&f.m);
576ec7da
AS
1567 goto end;
1568 }
cd3e32ce 1569 SCMutexUnlock(&f.m);
576ec7da 1570 if (smtp_state->input_len != 0 ||
576ec7da
AS
1571 smtp_state->cmds_cnt != 1 ||
1572 smtp_state->cmds_idx != 0 ||
1573 smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
1574 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
1575 printf("smtp parser in inconsistent state\n");
1576 goto end;
1577 }
1578
cd3e32ce 1579 SCMutexLock(&f.m);
997eaf42 1580 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
576ec7da
AS
1581 reply5, reply5_len);
1582 if (r != 0) {
1583 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1584 SCMutexUnlock(&f.m);
576ec7da
AS
1585 goto end;
1586 }
cd3e32ce 1587 SCMutexUnlock(&f.m);
576ec7da 1588 if (smtp_state->input_len != 0 ||
576ec7da
AS
1589 smtp_state->cmds_cnt != 0 ||
1590 smtp_state->cmds_idx != 0 ||
1591 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
1592 printf("smtp parser in inconsistent state\n");
1593 goto end;
1594 }
1595
cd3e32ce 1596 SCMutexLock(&f.m);
997eaf42 1597 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
576ec7da
AS
1598 request6, request6_len);
1599 if (r != 0) {
1600 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1601 SCMutexUnlock(&f.m);
576ec7da
AS
1602 goto end;
1603 }
cd3e32ce 1604 SCMutexUnlock(&f.m);
576ec7da 1605 if (smtp_state->input_len != 0 ||
576ec7da
AS
1606 smtp_state->cmds_cnt != 1 ||
1607 smtp_state->cmds_idx != 0 ||
1608 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1609 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1610 printf("smtp parser in inconsistent state\n");
1611 goto end;
1612 }
1613
cd3e32ce 1614 SCMutexLock(&f.m);
997eaf42 1615 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
576ec7da
AS
1616 reply6, reply6_len);
1617 if (r != 0) {
1618 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1619 SCMutexUnlock(&f.m);
576ec7da
AS
1620 goto end;
1621 }
cd3e32ce 1622 SCMutexUnlock(&f.m);
576ec7da 1623 if (smtp_state->input_len != 0 ||
576ec7da
AS
1624 smtp_state->cmds_cnt != 0 ||
1625 smtp_state->cmds_idx != 0 ||
1626 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
1627 printf("smtp parser in inconsistent state\n");
1628 goto end;
1629 }
1630
cd3e32ce 1631 SCMutexLock(&f.m);
997eaf42 1632 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
576ec7da
AS
1633 request7, request7_len);
1634 if (r != 0) {
1635 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1636 SCMutexUnlock(&f.m);
576ec7da
AS
1637 goto end;
1638 }
cd3e32ce 1639 SCMutexUnlock(&f.m);
576ec7da 1640 if (smtp_state->input_len != 0 ||
576ec7da
AS
1641 smtp_state->cmds_cnt != 1 ||
1642 smtp_state->cmds_idx != 0 ||
1643 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1644 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1645 printf("smtp parser in inconsistent state\n");
1646 goto end;
1647 }
1648
cd3e32ce 1649 SCMutexLock(&f.m);
997eaf42 1650 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
576ec7da
AS
1651 reply7, reply7_len);
1652 if (r != 0) {
1653 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1654 SCMutexUnlock(&f.m);
576ec7da
AS
1655 goto end;
1656 }
cd3e32ce 1657 SCMutexUnlock(&f.m);
576ec7da 1658 if (smtp_state->input_len != 0 ||
576ec7da
AS
1659 smtp_state->cmds_cnt != 0 ||
1660 smtp_state->cmds_idx != 0 ||
1661 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
1662 printf("smtp parser in inconsistent state\n");
1663 goto end;
1664 }
1665
cd3e32ce 1666 SCMutexLock(&f.m);
997eaf42 1667 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
576ec7da
AS
1668 request8, request8_len);
1669 if (r != 0) {
1670 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1671 SCMutexUnlock(&f.m);
576ec7da
AS
1672 goto end;
1673 }
cd3e32ce 1674 SCMutexUnlock(&f.m);
576ec7da 1675 if (smtp_state->input_len != 0 ||
576ec7da
AS
1676 smtp_state->cmds_cnt != 1 ||
1677 smtp_state->cmds_idx != 0 ||
1678 smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
1679 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1680 printf("smtp parser in inconsistent state\n");
1681 goto end;
1682 }
1683
cd3e32ce 1684 SCMutexLock(&f.m);
997eaf42 1685 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
576ec7da
AS
1686 reply8, reply8_len);
1687 if (r != 0) {
1688 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1689 SCMutexUnlock(&f.m);
576ec7da
AS
1690 goto end;
1691 }
cd3e32ce 1692 SCMutexUnlock(&f.m);
576ec7da 1693 if (smtp_state->input_len != 0 ||
576ec7da
AS
1694 smtp_state->cmds_cnt != 0 ||
1695 smtp_state->cmds_idx != 0 ||
1696 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
1697 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1698 printf("smtp parser in inconsistent state\n");
1699 goto end;
1700 }
1701
cd3e32ce 1702 SCMutexLock(&f.m);
997eaf42 1703 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
576ec7da
AS
1704 request9_1, request9_1_len);
1705 if (r != 0) {
1706 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1707 SCMutexUnlock(&f.m);
576ec7da
AS
1708 goto end;
1709 }
cd3e32ce 1710 SCMutexUnlock(&f.m);
576ec7da 1711 if (smtp_state->input_len != 0 ||
576ec7da
AS
1712 smtp_state->cmds_cnt != 0 ||
1713 smtp_state->cmds_idx != 0 ||
1714 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
1715 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1716
1717 printf("smtp parser in inconsistent state\n");
1718 goto end;
1719 }
1720
cd3e32ce 1721 SCMutexLock(&f.m);
997eaf42 1722 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
576ec7da
AS
1723 request9_2, request9_2_len);
1724 if (r != 0) {
1725 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1726 SCMutexUnlock(&f.m);
576ec7da
AS
1727 goto end;
1728 }
cd3e32ce 1729 SCMutexUnlock(&f.m);
576ec7da 1730 if (smtp_state->input_len != 0 ||
576ec7da
AS
1731 smtp_state->cmds_cnt != 0 ||
1732 smtp_state->cmds_idx != 0 ||
1733 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
1734 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1735
1736 printf("smtp parser in inconsistent state\n");
1737 goto end;
1738 }
1739
cd3e32ce 1740 SCMutexLock(&f.m);
997eaf42 1741 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
576ec7da
AS
1742 request9_3, request9_3_len);
1743 if (r != 0) {
1744 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1745 SCMutexUnlock(&f.m);
576ec7da
AS
1746 goto end;
1747 }
cd3e32ce 1748 SCMutexUnlock(&f.m);
576ec7da 1749 if (smtp_state->input_len != 0 ||
576ec7da
AS
1750 smtp_state->cmds_cnt != 0 ||
1751 smtp_state->cmds_idx != 0 ||
1752 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
1753 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1754
1755 printf("smtp parser in inconsistent state\n");
1756 goto end;
1757 }
1758
cd3e32ce 1759 SCMutexLock(&f.m);
997eaf42 1760 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
576ec7da
AS
1761 request9_4, request9_4_len);
1762 if (r != 0) {
1763 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1764 SCMutexUnlock(&f.m);
576ec7da
AS
1765 goto end;
1766 }
cd3e32ce 1767 SCMutexUnlock(&f.m);
576ec7da 1768 if (smtp_state->input_len != 0 ||
576ec7da
AS
1769 smtp_state->cmds_cnt != 0 ||
1770 smtp_state->cmds_idx != 0 ||
1771 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
1772 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1773
1774 printf("smtp parser in inconsistent state\n");
1775 goto end;
1776 }
1777
cd3e32ce 1778 SCMutexLock(&f.m);
997eaf42 1779 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
576ec7da
AS
1780 request9_5, request9_5_len);
1781 if (r != 0) {
1782 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1783 SCMutexUnlock(&f.m);
576ec7da
AS
1784 goto end;
1785 }
cd3e32ce 1786 SCMutexUnlock(&f.m);
576ec7da 1787 if (smtp_state->input_len != 0 ||
576ec7da
AS
1788 smtp_state->cmds_cnt != 1 ||
1789 smtp_state->cmds_idx != 0 ||
1790 smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
1791 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
1792 printf("smtp parser in inconsistent state\n");
1793 goto end;
1794 }
1795
cd3e32ce 1796 SCMutexLock(&f.m);
997eaf42 1797 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
576ec7da
AS
1798 reply9, reply9_len);
1799 if (r != 0) {
1800 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1801 SCMutexUnlock(&f.m);
576ec7da
AS
1802 goto end;
1803 }
cd3e32ce 1804 SCMutexUnlock(&f.m);
576ec7da 1805 if (smtp_state->input_len != 0 ||
576ec7da
AS
1806 smtp_state->cmds_cnt != 0 ||
1807 smtp_state->cmds_idx != 0 ||
1808 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
1809 printf("smtp parser in inconsistent state\n");
1810 goto end;
1811 }
1812
cd3e32ce 1813 SCMutexLock(&f.m);
997eaf42 1814 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
576ec7da
AS
1815 request10, request10_len);
1816 if (r != 0) {
1817 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1818 SCMutexUnlock(&f.m);
576ec7da
AS
1819 goto end;
1820 }
cd3e32ce 1821 SCMutexUnlock(&f.m);
576ec7da 1822 if (smtp_state->input_len != 0 ||
576ec7da
AS
1823 smtp_state->cmds_cnt != 1 ||
1824 smtp_state->cmds_idx != 0 ||
1825 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1826 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1827 printf("smtp parser in inconsistent state\n");
1828 goto end;
1829 }
1830
cd3e32ce 1831 SCMutexLock(&f.m);
997eaf42 1832 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
576ec7da
AS
1833 reply10, reply10_len);
1834 if (r != 0) {
1835 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1836 SCMutexUnlock(&f.m);
576ec7da
AS
1837 goto end;
1838 }
cd3e32ce 1839 SCMutexUnlock(&f.m);
576ec7da 1840 if (smtp_state->input_len != 0 ||
576ec7da
AS
1841 smtp_state->cmds_cnt != 0 ||
1842 smtp_state->cmds_idx != 0 ||
1843 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
1844 printf("smtp parser in inconsistent state\n");
1845 goto end;
1846 }
1847
1848 result = 1;
1849end:
576ec7da
AS
1850 StreamTcpFreeConfig(TRUE);
1851 FLOW_DESTROY(&f);
997eaf42 1852 SMTPLocalStorageFree(thread_local_data);
576ec7da
AS
1853 return result;
1854}
1855
1856/**
1857 * \test Testing parsing pipelined commands.
1858 */
1859int SMTPParserTest03(void)
1860{
1861 int result = 0;
1862 Flow f;
1863 int r = 0;
1864
1865 /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
1866 uint8_t welcome_reply[] = {
1867 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
1868 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
1869 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
1870 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
1871 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
1872 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
1873 };
1874 uint32_t welcome_reply_len = sizeof(welcome_reply);
1875
1876 /* EHLO boo.com<CR><LF> */
1877 uint8_t request1[] = {
1878 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
1879 0x2e, 0x63, 0x6f, 0x6d, 0x0a
1880 };
1881 uint32_t request1_len = sizeof(request1);
1882 /* 250-poona_slack_vm1.localdomain<CR><LF>
1883 * 250-PIPELINING<CR><LF>
1884 * 250-SIZE 10240000<CR><LF>
1885 * 250-VRFY<CR><LF>
1886 * 250-ETRN<CR><LF>
1887 * 250-ENHANCEDSTATUSCODES<CR><LF>
1888 * 250-8BITMIME<CR><LF>
1889 * 250 DSN<CR><LF>
1890 */
1891 uint8_t reply1[] = {
1892 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
1893 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
1894 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
1895 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
1896 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
1897 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
1898 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
1899 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
1900 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
1901 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
1902 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
1903 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
1904 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
1905 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
1906 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
1907 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
1908 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
1909 };
1910 uint32_t reply1_len = sizeof(reply1);
1911
1912 /* MAIL FROM:pbsf@asdfs.com<CR><LF>
1913 * RCPT TO:pbsf@asdfs.com<CR><LF>
1914 * DATA<CR><LF>
1915 */
1916 uint8_t request2[] = {
1917 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
1918 0x4d, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
1919 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
1920 0x0d, 0x0a, 0x52, 0x43, 0x50, 0x54, 0x20, 0x54,
1921 0x4f, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
1922 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
1923 0x0d, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
1924 };
1925 uint32_t request2_len = sizeof(request2);
1926 /* 250 2.1.0 Ok<CR><LF>
1927 * 250 2.1.5 Ok<CR><LF>
1928 * 354 End data with <CR><LF>.<CR><LF>|<CR><LF>|
1929 */
1930 uint8_t reply2[] = {
1931 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
1932 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a, 0x32, 0x35,
1933 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, 0x35, 0x20,
1934 0x4f, 0x6b, 0x0d, 0x0a, 0x33, 0x35, 0x34, 0x20,
1935 0x45, 0x6e, 0x64, 0x20, 0x64, 0x61, 0x74, 0x61,
1936 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x3c, 0x43,
1937 0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x2e, 0x3c,
1938 0x43, 0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x0d,
1939 0x0a
1940 };
1941 uint32_t reply2_len = sizeof(reply2);
1942
1943 TcpSession ssn;
1944
1945 memset(&f, 0, sizeof(f));
1946 memset(&ssn, 0, sizeof(ssn));
1947
1948 FLOW_INITIALIZE(&f);
1949 f.protoctx = (void *)&ssn;
1950
1951 StreamTcpInitConfig(TRUE);
997eaf42 1952 void *thread_local_data = SMTPLocalStorageAlloc();
576ec7da 1953
cd3e32ce 1954 SCMutexLock(&f.m);
0d7159b5
AS
1955 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
1956 welcome_reply, welcome_reply_len);
576ec7da
AS
1957 if (r != 0) {
1958 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1959 SCMutexUnlock(&f.m);
576ec7da
AS
1960 goto end;
1961 }
cd3e32ce 1962 SCMutexUnlock(&f.m);
06904c90 1963 SMTPState *smtp_state = f.alstate;
576ec7da
AS
1964 if (smtp_state == NULL) {
1965 printf("no smtp state: ");
1966 goto end;
1967 }
1968 if (smtp_state->input_len != 0 ||
0d7159b5 1969 smtp_state->cmds_cnt != 0 ||
576ec7da 1970 smtp_state->cmds_idx != 0 ||
0d7159b5 1971 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
576ec7da
AS
1972 printf("smtp parser in inconsistent state\n");
1973 goto end;
1974 }
1975
cd3e32ce 1976 SCMutexLock(&f.m);
0d7159b5
AS
1977 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
1978 request1, request1_len);
576ec7da
AS
1979 if (r != 0) {
1980 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1981 SCMutexUnlock(&f.m);
576ec7da
AS
1982 goto end;
1983 }
cd3e32ce 1984 SCMutexUnlock(&f.m);
576ec7da 1985 if (smtp_state->input_len != 0 ||
576ec7da
AS
1986 smtp_state->cmds_cnt != 1 ||
1987 smtp_state->cmds_idx != 0 ||
1988 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1989 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1990 printf("smtp parser in inconsistent state\n");
1991 goto end;
1992 }
1993
cd3e32ce 1994 SCMutexLock(&f.m);
997eaf42 1995 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
576ec7da
AS
1996 reply1, reply1_len);
1997 if (r != 0) {
1998 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1999 SCMutexUnlock(&f.m);
576ec7da
AS
2000 goto end;
2001 }
cd3e32ce 2002 SCMutexUnlock(&f.m);
576ec7da 2003 if (smtp_state->input_len != 0 ||
576ec7da
AS
2004 smtp_state->cmds_cnt != 0 ||
2005 smtp_state->cmds_idx != 0 ||
2006 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2007 printf("smtp parser in inconsistent state\n");
2008 goto end;
2009 }
2010
cd3e32ce 2011 SCMutexLock(&f.m);
997eaf42 2012 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
576ec7da
AS
2013 request2, request2_len);
2014 if (r != 0) {
2015 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2016 SCMutexUnlock(&f.m);
576ec7da
AS
2017 goto end;
2018 }
cd3e32ce 2019 SCMutexUnlock(&f.m);
576ec7da 2020 if (smtp_state->input_len != 0 ||
576ec7da
AS
2021 smtp_state->cmds_cnt != 3 ||
2022 smtp_state->cmds_idx != 0 ||
2023 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2024 smtp_state->cmds[1] != SMTP_COMMAND_OTHER_CMD ||
2025 smtp_state->cmds[2] != SMTP_COMMAND_DATA ||
2026 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2027 printf("smtp parser in inconsistent state\n");
2028 goto end;
2029 }
2030
cd3e32ce 2031 SCMutexLock(&f.m);
997eaf42 2032 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
576ec7da
AS
2033 reply2, reply2_len);
2034 if (r != 0) {
2035 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2036 SCMutexUnlock(&f.m);
576ec7da
AS
2037 goto end;
2038 }
cd3e32ce 2039 SCMutexUnlock(&f.m);
576ec7da 2040 if (smtp_state->input_len != 0 ||
576ec7da
AS
2041 smtp_state->cmds_cnt != 0 ||
2042 smtp_state->cmds_idx != 0 ||
2043 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2044 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
2045 printf("smtp parser in inconsistent state\n");
2046 goto end;
2047 }
2048
2049 result = 1;
2050end:
576ec7da
AS
2051 StreamTcpFreeConfig(TRUE);
2052 FLOW_DESTROY(&f);
997eaf42 2053 SMTPLocalStorageFree(thread_local_data);
576ec7da
AS
2054 return result;
2055}
2056
2057/*
2058 * \test Test smtp with just <LF> delimter instead of <CR><LF>.
2059 */
2060int SMTPParserTest04(void)
2061{
2062 int result = 0;
2063 Flow f;
2064 int r = 0;
2065
2066 /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
2067 uint8_t welcome_reply[] = {
2068 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
2069 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2070 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2071 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
2072 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
2073 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
2074 };
2075 uint32_t welcome_reply_len = sizeof(welcome_reply);
2076
2077 /* EHLO boo.com<CR><LF> */
2078 uint8_t request1[] = {
2079 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
2080 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2081 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2082 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
2083 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
2084 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
2085 };
2086 uint32_t request1_len = sizeof(request1);
2087
2088 TcpSession ssn;
2089
2090 memset(&f, 0, sizeof(f));
2091 memset(&ssn, 0, sizeof(ssn));
2092
2093 FLOW_INITIALIZE(&f);
2094 f.protoctx = (void *)&ssn;
2095
2096 StreamTcpInitConfig(TRUE);
997eaf42 2097 void *thread_local_data = SMTPLocalStorageAlloc();
576ec7da 2098
cd3e32ce 2099 SCMutexLock(&f.m);
0d7159b5
AS
2100 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
2101 welcome_reply, welcome_reply_len);
576ec7da
AS
2102 if (r != 0) {
2103 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2104 SCMutexUnlock(&f.m);
576ec7da
AS
2105 goto end;
2106 }
cd3e32ce 2107 SCMutexUnlock(&f.m);
06904c90 2108 SMTPState *smtp_state = f.alstate;
576ec7da
AS
2109 if (smtp_state == NULL) {
2110 printf("no smtp state: ");
2111 goto end;
2112 }
2113 if (smtp_state->input_len != 0 ||
0d7159b5 2114 smtp_state->cmds_cnt != 0 ||
576ec7da 2115 smtp_state->cmds_idx != 0 ||
0d7159b5 2116 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
576ec7da
AS
2117 printf("smtp parser in inconsistent state\n");
2118 goto end;
2119 }
2120
cd3e32ce 2121 SCMutexLock(&f.m);
0d7159b5
AS
2122 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2123 request1, request1_len);
576ec7da
AS
2124 if (r != 0) {
2125 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2126 SCMutexUnlock(&f.m);
576ec7da
AS
2127 goto end;
2128 }
cd3e32ce 2129 SCMutexUnlock(&f.m);
576ec7da 2130 if (smtp_state->input_len != 0 ||
576ec7da
AS
2131 smtp_state->cmds_cnt != 1 ||
2132 smtp_state->cmds_idx != 0 ||
2133 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2134 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2135 printf("smtp parser in inconsistent state\n");
2136 goto end;
2137 }
2138
2139 result = 1;
2140end:
576ec7da
AS
2141 StreamTcpFreeConfig(TRUE);
2142 FLOW_DESTROY(&f);
997eaf42 2143 SMTPLocalStorageFree(thread_local_data);
576ec7da
AS
2144 return result;
2145}
2146
2147/*
2148 * \test Test STARTTLS fail.
2149 */
2150int SMTPParserTest05(void)
2151{
2152 int result = 0;
2153 Flow f;
2154 int r = 0;
2155
2156 /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
2157 uint8_t welcome_reply[] = {
2158 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
2159 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2160 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2161 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
2162 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
2163 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
2164 };
2165 uint32_t welcome_reply_len = sizeof(welcome_reply);
2166
2167 /* EHLO boo.com<CR><LF> */
2168 uint8_t request1[] = {
2169 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
2170 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
2171 };
2172 uint32_t request1_len = sizeof(request1);
2173 /* 250-poona_slack_vm1.localdomain<CR><LF>
2174 * 250-PIPELINING<CR><LF>
2175 * 250-SIZE 10240000<CR><LF>
2176 * 250-VRFY<CR><LF>
2177 * 250-ETRN<CR><LF>
2178 * 250-ENHANCEDSTATUSCODES<CR><LF>
2179 * 250-8BITMIME<CR><LF>
2180 * 250 DSN<CR><LF>
2181 */
2182 uint8_t reply1[] = {
2183 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
2184 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2185 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2186 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
2187 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
2188 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
2189 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
2190 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
2191 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
2192 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
2193 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
2194 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
2195 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
2196 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
2197 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
2198 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
2199 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
2200 };
2201 uint32_t reply1_len = sizeof(reply1);
2202
2203 /* STARTTLS<CR><LF> */
2204 uint8_t request2[] = {
2205 0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
2206 0x0d, 0x0a
2207 };
2208 uint32_t request2_len = sizeof(request2);
2209 /* 502 5.5.2 Error: command not recognized<CR><LF> */
2210 uint8_t reply2[] = {
2211 0x35, 0x30, 0x32, 0x20, 0x35, 0x2e, 0x35, 0x2e,
2212 0x32, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x3a,
2213 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
2214 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x63,
2215 0x6f, 0x67, 0x6e, 0x69, 0x7a, 0x65, 0x64, 0x0d,
2216 0x0a
2217 };
2218 uint32_t reply2_len = sizeof(reply2);
2219
2220 /* QUIT<CR><LF> */
2221 uint8_t request3[] = {
2222 0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
2223
2224 };
2225 uint32_t request3_len = sizeof(request3);
2226 /* 221 2.0.0 Bye<CR><LF> */
2227 uint8_t reply3[] = {
2228 0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
2229 0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
2230 };
2231 uint32_t reply3_len = sizeof(reply3);
2232
2233 TcpSession ssn;
2234
2235 memset(&f, 0, sizeof(f));
2236 memset(&ssn, 0, sizeof(ssn));
2237
2238 FLOW_INITIALIZE(&f);
2239 f.protoctx = (void *)&ssn;
2240
2241 StreamTcpInitConfig(TRUE);
997eaf42 2242 void *thread_local_data = SMTPLocalStorageAlloc();
576ec7da 2243
cd3e32ce 2244 SCMutexLock(&f.m);
0d7159b5
AS
2245 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
2246 welcome_reply, welcome_reply_len);
576ec7da
AS
2247 if (r != 0) {
2248 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2249 SCMutexUnlock(&f.m);
576ec7da
AS
2250 goto end;
2251 }
cd3e32ce 2252 SCMutexUnlock(&f.m);
06904c90 2253 SMTPState *smtp_state = f.alstate;
576ec7da
AS
2254 if (smtp_state == NULL) {
2255 printf("no smtp state: ");
2256 goto end;
2257 }
2258 if (smtp_state->input_len != 0 ||
0d7159b5 2259 smtp_state->cmds_cnt != 0 ||
576ec7da 2260 smtp_state->cmds_idx != 0 ||
0d7159b5 2261 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
576ec7da
AS
2262 printf("smtp parser in inconsistent state\n");
2263 goto end;
2264 }
2265
cd3e32ce 2266 SCMutexLock(&f.m);
0d7159b5
AS
2267 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2268 request1, request1_len);
576ec7da
AS
2269 if (r != 0) {
2270 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2271 SCMutexUnlock(&f.m);
576ec7da
AS
2272 goto end;
2273 }
cd3e32ce 2274 SCMutexUnlock(&f.m);
576ec7da 2275 if (smtp_state->input_len != 0 ||
576ec7da
AS
2276 smtp_state->cmds_cnt != 1 ||
2277 smtp_state->cmds_idx != 0 ||
2278 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2279 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2280 printf("smtp parser in inconsistent state\n");
2281 goto end;
2282 }
2283
cd3e32ce 2284 SCMutexLock(&f.m);
997eaf42 2285 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
576ec7da
AS
2286 reply1, reply1_len);
2287 if (r != 0) {
2288 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2289 SCMutexUnlock(&f.m);
576ec7da
AS
2290 goto end;
2291 }
cd3e32ce 2292 SCMutexUnlock(&f.m);
576ec7da 2293 if (smtp_state->input_len != 0 ||
576ec7da
AS
2294 smtp_state->cmds_cnt != 0 ||
2295 smtp_state->cmds_idx != 0 ||
2296 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2297 printf("smtp parser in inconsistent state\n");
2298 goto end;
2299 }
2300
cd3e32ce 2301 SCMutexLock(&f.m);
997eaf42 2302 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
576ec7da
AS
2303 request2, request2_len);
2304 if (r != 0) {
2305 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2306 SCMutexUnlock(&f.m);
576ec7da
AS
2307 goto end;
2308 }
cd3e32ce 2309 SCMutexUnlock(&f.m);
576ec7da 2310 if (smtp_state->input_len != 0 ||
576ec7da
AS
2311 smtp_state->cmds_cnt != 1 ||
2312 smtp_state->cmds_idx != 0 ||
2313 smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS ||
2314 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2315 printf("smtp parser in inconsistent state\n");
2316 goto end;
2317 }
2318
cd3e32ce 2319 SCMutexLock(&f.m);
997eaf42 2320 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
576ec7da
AS
2321 reply2, reply2_len);
2322 if (r != 0) {
2323 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2324 SCMutexUnlock(&f.m);
576ec7da
AS
2325 goto end;
2326 }
cd3e32ce 2327 SCMutexUnlock(&f.m);
576ec7da 2328 if (smtp_state->input_len != 0 ||
576ec7da
AS
2329 smtp_state->cmds_cnt != 0 ||
2330 smtp_state->cmds_idx != 0 ||
2331 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2332 printf("smtp parser in inconsistent state\n");
2333 goto end;
2334 }
2335
2336 if ((f.flags & FLOW_NOPAYLOAD_INSPECTION) ||
2337 (f.flags & FLOW_NO_APPLAYER_INSPECTION) ||
2338 (((TcpSession *)f.protoctx)->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) ||
2339 (((TcpSession *)f.protoctx)->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
2340 goto end;
2341 }
2342
cd3e32ce 2343 SCMutexLock(&f.m);
997eaf42 2344 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
576ec7da
AS
2345 request3, request3_len);
2346 if (r != 0) {
2347 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2348 SCMutexUnlock(&f.m);
576ec7da
AS
2349 goto end;
2350 }
cd3e32ce 2351 SCMutexUnlock(&f.m);
576ec7da 2352 if (smtp_state->input_len != 0 ||
576ec7da
AS
2353 smtp_state->cmds_cnt != 1 ||
2354 smtp_state->cmds_idx != 0 ||
2355 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2356 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2357 printf("smtp parser in inconsistent state\n");
2358 goto end;
2359 }
2360
cd3e32ce 2361 SCMutexLock(&f.m);
997eaf42 2362 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
576ec7da
AS
2363 reply3, reply3_len);
2364 if (r != 0) {
2365 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2366 SCMutexUnlock(&f.m);
576ec7da
AS
2367 goto end;
2368 }
cd3e32ce 2369 SCMutexUnlock(&f.m);
576ec7da 2370 if (smtp_state->input_len != 0 ||
576ec7da
AS
2371 smtp_state->cmds_cnt != 0 ||
2372 smtp_state->cmds_idx != 0 ||
2373 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2374 printf("smtp parser in inconsistent state\n");
2375 goto end;
2376 }
2377
2378 result = 1;
2379end:
576ec7da
AS
2380 StreamTcpFreeConfig(TRUE);
2381 FLOW_DESTROY(&f);
997eaf42 2382 SMTPLocalStorageFree(thread_local_data);
576ec7da
AS
2383 return result;
2384}
2385
d3ca65de
AS
2386/**
2387 * \test Test multiple DATA commands(full mail transactions).
2388 */
2389int SMTPParserTest06(void)
2390{
2391 int result = 0;
2392 Flow f;
2393 int r = 0;
2394
2395 uint8_t welcome_reply[] = {
2396 0x32, 0x32, 0x30, 0x20, 0x62, 0x61, 0x79, 0x30,
2397 0x2d, 0x6d, 0x63, 0x36, 0x2d, 0x66, 0x31, 0x30,
2398 0x2e, 0x62, 0x61, 0x79, 0x30, 0x2e, 0x68, 0x6f,
2399 0x74, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f,
2400 0x6d, 0x20, 0x53, 0x65, 0x6e, 0x64, 0x69, 0x6e,
2401 0x67, 0x20, 0x75, 0x6e, 0x73, 0x6f, 0x6c, 0x69,
2402 0x63, 0x69, 0x74, 0x65, 0x64, 0x20, 0x63, 0x6f,
2403 0x6d, 0x6d, 0x65, 0x72, 0x63, 0x69, 0x61, 0x6c,
2404 0x20, 0x6f, 0x72, 0x20, 0x62, 0x75, 0x6c, 0x6b,
2405 0x20, 0x65, 0x2d, 0x6d, 0x61, 0x69, 0x6c, 0x20,
2406 0x74, 0x6f, 0x20, 0x4d, 0x69, 0x63, 0x72, 0x6f,
2407 0x73, 0x6f, 0x66, 0x74, 0x27, 0x73, 0x20, 0x63,
2408 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x20,
2409 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20,
2410 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x68, 0x69,
2411 0x62, 0x69, 0x74, 0x65, 0x64, 0x2e, 0x20, 0x4f,
2412 0x74, 0x68, 0x65, 0x72, 0x20, 0x72, 0x65, 0x73,
2413 0x74, 0x72, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e,
2414 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x66, 0x6f,
2415 0x75, 0x6e, 0x64, 0x20, 0x61, 0x74, 0x20, 0x68,
2416 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x72,
2417 0x69, 0x76, 0x61, 0x63, 0x79, 0x2e, 0x6d, 0x73,
2418 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x41, 0x6e,
2419 0x74, 0x69, 0x2d, 0x73, 0x70, 0x61, 0x6d, 0x2f,
2420 0x2e, 0x20, 0x56, 0x69, 0x6f, 0x6c, 0x61, 0x74,
2421 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x77, 0x69, 0x6c,
2422 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74,
2423 0x20, 0x69, 0x6e, 0x20, 0x75, 0x73, 0x65, 0x20,
2424 0x6f, 0x66, 0x20, 0x65, 0x71, 0x75, 0x69, 0x70,
2425 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x63,
2426 0x61, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20,
2427 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e,
2428 0x69, 0x61, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6f,
2429 0x74, 0x68, 0x65, 0x72, 0x20, 0x73, 0x74, 0x61,
2430 0x74, 0x65, 0x73, 0x2e, 0x20, 0x46, 0x72, 0x69,
2431 0x2c, 0x20, 0x31, 0x36, 0x20, 0x46, 0x65, 0x62,
2432 0x20, 0x32, 0x30, 0x30, 0x37, 0x20, 0x30, 0x35,
2433 0x3a, 0x30, 0x33, 0x3a, 0x32, 0x33, 0x20, 0x2d,
2434 0x30, 0x38, 0x30, 0x30, 0x20, 0x0d, 0x0a
2435 };
2436 uint32_t welcome_reply_len = sizeof(welcome_reply);
2437
2438 uint8_t request1[] = {
2439 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x45, 0x58, 0x43,
2440 0x48, 0x41, 0x4e, 0x47, 0x45, 0x32, 0x2e, 0x63,
2441 0x67, 0x63, 0x65, 0x6e, 0x74, 0x2e, 0x6d, 0x69,
2442 0x61, 0x6d, 0x69, 0x2e, 0x65, 0x64, 0x75, 0x0d,
2443 0x0a
2444 };
2445 uint32_t request1_len = sizeof(request1);
2446
2447 uint8_t reply1[] = {
2448 0x32, 0x35, 0x30, 0x2d, 0x62, 0x61, 0x79, 0x30,
2449 0x2d, 0x6d, 0x63, 0x36, 0x2d, 0x66, 0x31, 0x30,
2450 0x2e, 0x62, 0x61, 0x79, 0x30, 0x2e, 0x68, 0x6f,
2451 0x74, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f,
2452 0x6d, 0x20, 0x28, 0x33, 0x2e, 0x33, 0x2e, 0x31,
2453 0x2e, 0x34, 0x29, 0x20, 0x48, 0x65, 0x6c, 0x6c,
2454 0x6f, 0x20, 0x5b, 0x31, 0x32, 0x39, 0x2e, 0x31,
2455 0x37, 0x31, 0x2e, 0x33, 0x32, 0x2e, 0x35, 0x39,
2456 0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53,
2457 0x49, 0x5a, 0x45, 0x20, 0x32, 0x39, 0x36, 0x39,
2458 0x36, 0x30, 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35,
2459 0x30, 0x2d, 0x50, 0x49, 0x50, 0x45, 0x4c, 0x49,
2460 0x4e, 0x49, 0x4e, 0x47, 0x0d, 0x0a, 0x32, 0x35,
2461 0x30, 0x2d, 0x38, 0x62, 0x69, 0x74, 0x6d, 0x69,
2462 0x6d, 0x65, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
2463 0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x4d, 0x49,
2464 0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
2465 0x43, 0x48, 0x55, 0x4e, 0x4b, 0x49, 0x4e, 0x47,
2466 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x41, 0x55,
2467 0x54, 0x48, 0x20, 0x4c, 0x4f, 0x47, 0x49, 0x4e,
2468 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x41, 0x55,
2469 0x54, 0x48, 0x3d, 0x4c, 0x4f, 0x47, 0x49, 0x4e,
2470 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20, 0x4f, 0x4b,
2471 0x0d, 0x0a
2472 };
2473 uint32_t reply1_len = sizeof(reply1);
2474
2475 /* MAIL FROM:asdff@asdf.com<CR><LF> */
2476 uint8_t request2[] = {
2477 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
2478 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
2479 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
2480 0x0d, 0x0a
2481 };
2482 uint32_t request2_len = sizeof(request2);
2483 /* 250 2.1.0 Ok<CR><LF> */
2484 uint8_t reply2[] = {
2485 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2486 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2487 };
2488 uint32_t reply2_len = sizeof(reply2);
2489
2490 /* RCPT TO:bimbs@gmail.com<CR><LF> */
2491 uint8_t request3[] = {
2492 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
2493 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
2494 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
2495 0x0a
2496 };
2497 uint32_t request3_len = sizeof(request3);
2498 /* 250 2.1.5 Ok<CR><LF> */
2499 uint8_t reply3[] = {
2500 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2501 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2502 };
2503 uint32_t reply3_len = sizeof(reply3);
2504
2505 /* BDAT 51<CR><LF> */
2506 uint8_t request4[] = {
2507 0x42, 0x44, 0x41, 0x54, 0x20, 0x35, 0x31, 0x0d,
2508 0x0a,
2509 };
2510 uint32_t request4_len = sizeof(request4);
2511
2512 uint8_t request5[] = {
2513 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
2514 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
2515 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
2516 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x0d, 0x0a,
2517 };
2518 uint32_t request5_len = sizeof(request5);
2519
2520 uint8_t request6[] = {
2521 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
2522 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
2523 0x66, 0x0d, 0x0a,
2524 };
561630d8 2525 uint32_t request6_len = sizeof(request6);
d3ca65de
AS
2526
2527 TcpSession ssn;
2528
2529 memset(&f, 0, sizeof(f));
2530 memset(&ssn, 0, sizeof(ssn));
2531
2532 FLOW_INITIALIZE(&f);
2533 f.protoctx = (void *)&ssn;
2534
2535 StreamTcpInitConfig(TRUE);
997eaf42 2536 void *thread_local_data = SMTPLocalStorageAlloc();
d3ca65de 2537
cd3e32ce 2538 SCMutexLock(&f.m);
0d7159b5
AS
2539 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
2540 welcome_reply, welcome_reply_len);
d3ca65de
AS
2541 if (r != 0) {
2542 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2543 SCMutexUnlock(&f.m);
d3ca65de
AS
2544 goto end;
2545 }
cd3e32ce 2546 SCMutexUnlock(&f.m);
06904c90 2547 SMTPState *smtp_state = f.alstate;
d3ca65de
AS
2548 if (smtp_state == NULL) {
2549 printf("no smtp state: ");
2550 goto end;
2551 }
2552 if (smtp_state->input_len != 0 ||
0d7159b5 2553 smtp_state->cmds_cnt != 0 ||
d3ca65de 2554 smtp_state->cmds_idx != 0 ||
0d7159b5 2555 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
d3ca65de
AS
2556 printf("smtp parser in inconsistent state\n");
2557 goto end;
2558 }
2559
cd3e32ce 2560 SCMutexLock(&f.m);
0d7159b5
AS
2561 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2562 request1, request1_len);
d3ca65de
AS
2563 if (r != 0) {
2564 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2565 SCMutexUnlock(&f.m);
d3ca65de
AS
2566 goto end;
2567 }
cd3e32ce 2568 SCMutexUnlock(&f.m);
d3ca65de
AS
2569 if (smtp_state->input_len != 0 ||
2570 smtp_state->cmds_cnt != 1 ||
2571 smtp_state->cmds_idx != 0 ||
2572 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2573 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2574 printf("smtp parser in inconsistent state\n");
2575 goto end;
2576 }
2577
cd3e32ce 2578 SCMutexLock(&f.m);
997eaf42 2579 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
d3ca65de
AS
2580 reply1, reply1_len);
2581 if (r != 0) {
2582 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2583 SCMutexUnlock(&f.m);
d3ca65de
AS
2584 goto end;
2585 }
cd3e32ce 2586 SCMutexUnlock(&f.m);
d3ca65de
AS
2587 if (smtp_state->input_len != 0 ||
2588 smtp_state->cmds_cnt != 0 ||
2589 smtp_state->cmds_idx != 0 ||
2590 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2591 printf("smtp parser in inconsistent state\n");
2592 goto end;
2593 }
2594
cd3e32ce 2595 SCMutexLock(&f.m);
997eaf42 2596 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
d3ca65de
AS
2597 request2, request2_len);
2598 if (r != 0) {
2599 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2600 SCMutexUnlock(&f.m);
d3ca65de
AS
2601 goto end;
2602 }
cd3e32ce 2603 SCMutexUnlock(&f.m);
d3ca65de
AS
2604 if (smtp_state->input_len != 0 ||
2605 smtp_state->cmds_cnt != 1 ||
2606 smtp_state->cmds_idx != 0 ||
2607 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2608 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2609 printf("smtp parser in inconsistent state\n");
2610 goto end;
2611 }
2612
cd3e32ce 2613 SCMutexLock(&f.m);
997eaf42 2614 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
d3ca65de
AS
2615 reply2, reply2_len);
2616 if (r != 0) {
2617 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2618 SCMutexUnlock(&f.m);
d3ca65de
AS
2619 goto end;
2620 }
cd3e32ce 2621 SCMutexUnlock(&f.m);
d3ca65de
AS
2622 if (smtp_state->input_len != 0 ||
2623 smtp_state->cmds_cnt != 0 ||
2624 smtp_state->cmds_idx != 0 ||
2625 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2626 printf("smtp parser in inconsistent state\n");
2627 goto end;
2628 }
2629
cd3e32ce 2630 SCMutexLock(&f.m);
997eaf42 2631 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
d3ca65de
AS
2632 request3, request3_len);
2633 if (r != 0) {
2634 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2635 SCMutexUnlock(&f.m);
d3ca65de
AS
2636 goto end;
2637 }
cd3e32ce 2638 SCMutexUnlock(&f.m);
d3ca65de
AS
2639 if (smtp_state->input_len != 0 ||
2640 smtp_state->cmds_cnt != 1 ||
2641 smtp_state->cmds_idx != 0 ||
2642 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2643 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2644 printf("smtp parser in inconsistent state\n");
2645 goto end;
2646 }
2647
cd3e32ce 2648 SCMutexLock(&f.m);
997eaf42 2649 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
d3ca65de
AS
2650 reply3, reply3_len);
2651 if (r != 0) {
2652 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2653 SCMutexUnlock(&f.m);
d3ca65de
AS
2654 goto end;
2655 }
cd3e32ce 2656 SCMutexUnlock(&f.m);
d3ca65de
AS
2657 if (smtp_state->input_len != 0 ||
2658 smtp_state->cmds_cnt != 0 ||
2659 smtp_state->cmds_idx != 0 ||
2660 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2661 printf("smtp parser in inconsistent state\n");
2662 goto end;
2663 }
2664
cd3e32ce 2665 SCMutexLock(&f.m);
997eaf42 2666 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
d3ca65de
AS
2667 request4, request4_len);
2668 if (r != 0) {
2669 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2670 SCMutexUnlock(&f.m);
d3ca65de
AS
2671 goto end;
2672 }
cd3e32ce 2673 SCMutexUnlock(&f.m);
d3ca65de
AS
2674 if (smtp_state->input_len != 0 ||
2675 smtp_state->cmds_cnt != 1 ||
2676 smtp_state->cmds_idx != 0 ||
2677 smtp_state->cmds[0] != SMTP_COMMAND_BDAT ||
2678 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2679 SMTP_PARSER_STATE_COMMAND_DATA_MODE) ||
2680 smtp_state->bdat_chunk_len != 51 ||
2681 smtp_state->bdat_chunk_idx != 0) {
2682 printf("smtp parser in inconsistent state\n");
2683 goto end;
2684 }
2685
cd3e32ce 2686 SCMutexLock(&f.m);
997eaf42 2687 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
d3ca65de
AS
2688 request5, request5_len);
2689 if (r != 0) {
2690 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2691 SCMutexUnlock(&f.m);
d3ca65de
AS
2692 goto end;
2693 }
cd3e32ce 2694 SCMutexUnlock(&f.m);
d3ca65de
AS
2695 if (smtp_state->input_len != 0 ||
2696 smtp_state->cmds_cnt != 1 ||
2697 smtp_state->cmds_idx != 0 ||
2698 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2699 SMTP_PARSER_STATE_COMMAND_DATA_MODE) ||
2700 smtp_state->bdat_chunk_len != 51 ||
2701 smtp_state->bdat_chunk_idx != 32) {
2702 printf("smtp parser in inconsistent state\n");
2703 goto end;
2704 }
2705
cd3e32ce 2706 SCMutexLock(&f.m);
997eaf42 2707 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
d3ca65de
AS
2708 request6, request6_len);
2709 if (r != 0) {
2710 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2711 SCMutexUnlock(&f.m);
d3ca65de
AS
2712 goto end;
2713 }
cd3e32ce 2714 SCMutexUnlock(&f.m);
d3ca65de
AS
2715 if (smtp_state->input_len != 0 ||
2716 smtp_state->cmds_cnt != 1 ||
2717 smtp_state->cmds_idx != 0 ||
2718 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN ||
2719 smtp_state->bdat_chunk_len != 51 ||
2720 smtp_state->bdat_chunk_idx != 51) {
2721 printf("smtp parser in inconsistent state\n");
2722 goto end;
2723 }
2724
2725 result = 1;
2726end:
d3ca65de
AS
2727 StreamTcpFreeConfig(TRUE);
2728 FLOW_DESTROY(&f);
997eaf42 2729 SMTPLocalStorageFree(thread_local_data);
d3ca65de
AS
2730 return result;
2731}
2732
4a6908d3
AS
2733/*
2734 * \test Test retrieving lines when frag'ed.
2735 */
2736int SMTPParserTest07(void)
2737{
2738 int result = 0;
2739 Flow f;
2740 int r = 0;
2741
2742 const char *request1_str = "EHLO boo.com";
2743 /* EHLO boo.com<CR> */
2744 uint8_t request1_1[] = {
2745 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
2746 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
2747 };
2748 int32_t request1_1_len = sizeof(request1_1);
2749
2750 /* <LF> */
2751 uint8_t request1_2[] = {
2752 0x0a
2753 };
2754 int32_t request1_2_len = sizeof(request1_2);
2755
2756 /* EHLO boo.com<CR><LF> */
2757 uint8_t request2[] = {
2758 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
2759 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
2760 };
2761 int32_t request2_len = sizeof(request2);
2762
2763 TcpSession ssn;
2764
2765 memset(&f, 0, sizeof(f));
2766 memset(&ssn, 0, sizeof(ssn));
2767
2768 FLOW_INITIALIZE(&f);
2769 f.protoctx = (void *)&ssn;
2770
2771 StreamTcpInitConfig(TRUE);
997eaf42 2772 void *thread_local_data = SMTPLocalStorageAlloc();
4a6908d3 2773
cd3e32ce 2774 SCMutexLock(&f.m);
997eaf42 2775 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
4a6908d3
AS
2776 request1_1, request1_1_len);
2777 if (r != 0) {
2778 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2779 SCMutexUnlock(&f.m);
4a6908d3
AS
2780 goto end;
2781 }
cd3e32ce 2782 SCMutexUnlock(&f.m);
bf24272c 2783 SMTPState *smtp_state = f.alstate;
4a6908d3
AS
2784 if (smtp_state == NULL) {
2785 printf("no smtp state: ");
2786 goto end;
2787 }
2788 if (smtp_state->current_line != NULL ||
2789 smtp_state->current_line_len != 0 ||
2790 smtp_state->ts_current_line_db != 1 ||
2791 smtp_state->ts_db == NULL ||
2792 smtp_state->ts_db_len != request1_1_len ||
2793 memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) {
2794 printf("smtp parser in inconsistent state\n");
2795 goto end;
2796 }
2797
cd3e32ce 2798 SCMutexLock(&f.m);
997eaf42 2799 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
4a6908d3
AS
2800 request1_2, request1_2_len);
2801 if (r != 0) {
2802 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2803 SCMutexUnlock(&f.m);
4a6908d3
AS
2804 goto end;
2805 }
cd3e32ce 2806 SCMutexUnlock(&f.m);
4a6908d3
AS
2807 if (smtp_state->ts_current_line_db != 1 ||
2808 smtp_state->ts_db == NULL ||
2809 smtp_state->ts_db_len != (int32_t)strlen(request1_str) ||
2810 memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 ||
2811 smtp_state->current_line != smtp_state->ts_db ||
2812 smtp_state->current_line_len != smtp_state->ts_db_len) {
2813 printf("smtp parser in inconsistent state\n");
2814 goto end;
2815 }
2816
cd3e32ce 2817 SCMutexLock(&f.m);
997eaf42 2818 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
4a6908d3
AS
2819 request2, request2_len);
2820 if (r != 0) {
2821 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2822 SCMutexUnlock(&f.m);
4a6908d3
AS
2823 goto end;
2824 }
cd3e32ce 2825 SCMutexUnlock(&f.m);
4a6908d3
AS
2826 if (smtp_state->ts_current_line_db != 0 ||
2827 smtp_state->ts_db != NULL ||
2828 smtp_state->ts_db_len != 0 ||
2829 smtp_state->current_line == NULL ||
2830 smtp_state->current_line_len != (int32_t)strlen(request1_str) ||
2831 memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) {
2832 printf("smtp parser in inconsistent state\n");
2833 goto end;
2834 }
2835
2836 result = 1;
2837end:
4a6908d3
AS
2838 StreamTcpFreeConfig(TRUE);
2839 FLOW_DESTROY(&f);
997eaf42 2840 SMTPLocalStorageFree(thread_local_data);
4a6908d3
AS
2841 return result;
2842}
2843
2844/*
2845 * \test Test retrieving lines when frag'ed.
2846 */
2847int SMTPParserTest08(void)
2848{
2849 int result = 0;
2850 Flow f;
2851 int r = 0;
2852
2853 const char *request1_str = "EHLO boo.com";
2854 /* EHLO boo.com */
2855 uint8_t request1_1[] = {
2856 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
2857 0x2e, 0x63, 0x6f, 0x6d,
2858 };
2859 int32_t request1_1_len = sizeof(request1_1);
2860
2861 /* <CR><LF> */
2862 uint8_t request1_2[] = {
2863 0x0d, 0x0a
2864 };
2865 int32_t request1_2_len = sizeof(request1_2);
2866
2867 /* EHLO boo.com<CR><LF> */
2868 uint8_t request2[] = {
2869 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
2870 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
2871 };
2872 int32_t request2_len = sizeof(request2);
2873
2874 TcpSession ssn;
2875
2876 memset(&f, 0, sizeof(f));
2877 memset(&ssn, 0, sizeof(ssn));
2878
2879 FLOW_INITIALIZE(&f);
2880 f.protoctx = (void *)&ssn;
2881
2882 StreamTcpInitConfig(TRUE);
997eaf42 2883 void *thread_local_data = SMTPLocalStorageAlloc();
4a6908d3 2884
cd3e32ce 2885 SCMutexLock(&f.m);
997eaf42 2886 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
4a6908d3
AS
2887 request1_1, request1_1_len);
2888 if (r != 0) {
2889 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2890 SCMutexUnlock(&f.m);
4a6908d3
AS
2891 goto end;
2892 }
cd3e32ce 2893 SCMutexUnlock(&f.m);
bf24272c 2894 SMTPState *smtp_state = f.alstate;
4a6908d3
AS
2895 if (smtp_state == NULL) {
2896 printf("no smtp state: ");
2897 goto end;
2898 }
2899 if (smtp_state->current_line != NULL ||
2900 smtp_state->current_line_len != 0 ||
2901 smtp_state->ts_current_line_db != 1 ||
2902 smtp_state->ts_db == NULL ||
2903 smtp_state->ts_db_len != request1_1_len ||
2904 memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) {
2905 printf("smtp parser in inconsistent state\n");
2906 goto end;
2907 }
2908
cd3e32ce 2909 SCMutexLock(&f.m);
997eaf42 2910 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
4a6908d3
AS
2911 request1_2, request1_2_len);
2912 if (r != 0) {
2913 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2914 SCMutexUnlock(&f.m);
4a6908d3
AS
2915 goto end;
2916 }
cd3e32ce 2917 SCMutexUnlock(&f.m);
4a6908d3
AS
2918 if (smtp_state->ts_current_line_db != 1 ||
2919 smtp_state->ts_db == NULL ||
2920 smtp_state->ts_db_len != (int32_t)strlen(request1_str) ||
2921 memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 ||
2922 smtp_state->current_line != smtp_state->ts_db ||
2923 smtp_state->current_line_len != smtp_state->ts_db_len) {
2924 printf("smtp parser in inconsistent state\n");
2925 goto end;
2926 }
2927
cd3e32ce 2928 SCMutexLock(&f.m);
997eaf42 2929 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
4a6908d3
AS
2930 request2, request2_len);
2931 if (r != 0) {
2932 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2933 SCMutexUnlock(&f.m);
4a6908d3
AS
2934 goto end;
2935 }
cd3e32ce 2936 SCMutexUnlock(&f.m);
4a6908d3
AS
2937 if (smtp_state->ts_current_line_db != 0 ||
2938 smtp_state->ts_db != NULL ||
2939 smtp_state->ts_db_len != 0 ||
2940 smtp_state->current_line == NULL ||
2941 smtp_state->current_line_len != (int32_t)strlen(request1_str) ||
2942 memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) {
2943 printf("smtp parser in inconsistent state\n");
2944 goto end;
2945 }
2946
2947 result = 1;
2948end:
4a6908d3
AS
2949 StreamTcpFreeConfig(TRUE);
2950 FLOW_DESTROY(&f);
997eaf42 2951 SMTPLocalStorageFree(thread_local_data);
4a6908d3
AS
2952 return result;
2953}
2954
2955/*
2956 * \test Test retrieving lines when frag'ed.
2957 */
2958int SMTPParserTest09(void)
2959{
2960 int result = 0;
2961 Flow f;
2962 int r = 0;
2963
2964 const char *request1_str = "EHLO boo.com";
2965 /* EHLO boo. */
2966 uint8_t request1_1[] = {
2967 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
2968 0x2e,
2969 };
2970 int32_t request1_1_len = sizeof(request1_1);
2971
2972 /* com<CR><LF> */
2973 uint8_t request1_2[] = {
2974 0x63, 0x6f, 0x6d, 0x0d, 0x0a
2975 };
2976 int32_t request1_2_len = sizeof(request1_2);
2977
2978 /* EHLO boo.com<CR><LF> */
2979 uint8_t request2[] = {
2980 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
2981 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
2982 };
2983 int32_t request2_len = sizeof(request2);
2984
2985 TcpSession ssn;
2986
2987 memset(&f, 0, sizeof(f));
2988 memset(&ssn, 0, sizeof(ssn));
2989
2990 FLOW_INITIALIZE(&f);
2991 f.protoctx = (void *)&ssn;
2992
2993 StreamTcpInitConfig(TRUE);
997eaf42 2994 void *thread_local_data = SMTPLocalStorageAlloc();
4a6908d3 2995
cd3e32ce 2996 SCMutexLock(&f.m);
997eaf42 2997 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
4a6908d3
AS
2998 request1_1, request1_1_len);
2999 if (r != 0) {
3000 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3001 SCMutexUnlock(&f.m);
4a6908d3
AS
3002 goto end;
3003 }
cd3e32ce 3004 SCMutexUnlock(&f.m);
bf24272c 3005 SMTPState *smtp_state = f.alstate;
4a6908d3
AS
3006 if (smtp_state == NULL) {
3007 printf("no smtp state: ");
3008 goto end;
3009 }
3010 if (smtp_state->current_line != NULL ||
3011 smtp_state->current_line_len != 0 ||
3012 smtp_state->ts_current_line_db != 1 ||
3013 smtp_state->ts_db == NULL ||
3014 smtp_state->ts_db_len != request1_1_len ||
3015 memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) {
3016 printf("smtp parser in inconsistent state\n");
3017 goto end;
3018 }
3019
cd3e32ce 3020 SCMutexLock(&f.m);
997eaf42 3021 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
4a6908d3
AS
3022 request1_2, request1_2_len);
3023 if (r != 0) {
3024 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3025 SCMutexUnlock(&f.m);
4a6908d3
AS
3026 goto end;
3027 }
cd3e32ce 3028 SCMutexUnlock(&f.m);
4a6908d3
AS
3029 if (smtp_state->ts_current_line_db != 1 ||
3030 smtp_state->ts_db == NULL ||
3031 smtp_state->ts_db_len != (int32_t)strlen(request1_str) ||
3032 memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 ||
3033 smtp_state->current_line != smtp_state->ts_db ||
3034 smtp_state->current_line_len != smtp_state->ts_db_len) {
3035 printf("smtp parser in inconsistent state\n");
3036 goto end;
3037 }
3038
cd3e32ce 3039 SCMutexLock(&f.m);
997eaf42 3040 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
4a6908d3
AS
3041 request2, request2_len);
3042 if (r != 0) {
3043 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3044 SCMutexUnlock(&f.m);
4a6908d3
AS
3045 goto end;
3046 }
cd3e32ce 3047 SCMutexUnlock(&f.m);
4a6908d3
AS
3048 if (smtp_state->ts_current_line_db != 0 ||
3049 smtp_state->ts_db != NULL ||
3050 smtp_state->ts_db_len != 0 ||
3051 smtp_state->current_line == NULL ||
3052 smtp_state->current_line_len != (int32_t)strlen(request1_str) ||
3053 memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) {
3054 printf("smtp parser in inconsistent state\n");
3055 goto end;
3056 }
3057
3058 result = 1;
3059end:
4a6908d3
AS
3060 StreamTcpFreeConfig(TRUE);
3061 FLOW_DESTROY(&f);
997eaf42 3062 SMTPLocalStorageFree(thread_local_data);
4a6908d3
AS
3063 return result;
3064}
3065
3066/*
3067 * \test Test retrieving lines when frag'ed.
3068 */
3069int SMTPParserTest10(void)
3070{
3071 int result = 0;
3072 Flow f;
3073 int r = 0;
3074
3075 const char *request1_str = "";
3076 /* EHLO boo. */
3077 uint8_t request1_1[] = {
3078 0x0d,
3079 };
3080 int32_t request1_1_len = sizeof(request1_1);
3081
3082 /* com<CR><LF> */
3083 uint8_t request1_2[] = {
3084 0x0a,
3085 };
3086 int32_t request1_2_len = sizeof(request1_2);
3087
3088 const char *request2_str = "EHLO boo.com";
3089 /* EHLO boo.com<CR><LF> */
3090 uint8_t request2[] = {
3091 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3092 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3093 };
3094 int32_t request2_len = sizeof(request2);
3095
3096 TcpSession ssn;
3097
3098 memset(&f, 0, sizeof(f));
3099 memset(&ssn, 0, sizeof(ssn));
3100
3101 FLOW_INITIALIZE(&f);
3102 f.protoctx = (void *)&ssn;
3103
3104 StreamTcpInitConfig(TRUE);
997eaf42 3105 void *thread_local_data = SMTPLocalStorageAlloc();
4a6908d3 3106
cd3e32ce 3107 SCMutexLock(&f.m);
997eaf42 3108 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
4a6908d3
AS
3109 request1_1, request1_1_len);
3110 if (r != 0) {
3111 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3112 SCMutexUnlock(&f.m);
4a6908d3
AS
3113 goto end;
3114 }
cd3e32ce 3115 SCMutexUnlock(&f.m);
bf24272c 3116 SMTPState *smtp_state = f.alstate;
4a6908d3
AS
3117 if (smtp_state == NULL) {
3118 printf("no smtp state: ");
3119 goto end;
3120 }
3121 if (smtp_state->current_line != NULL ||
3122 smtp_state->current_line_len != 0 ||
3123 smtp_state->ts_current_line_db != 1 ||
3124 smtp_state->ts_db == NULL ||
3125 smtp_state->ts_db_len != request1_1_len ||
3126 memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) {
3127 printf("smtp parser in inconsistent state\n");
3128 goto end;
3129 }
3130
cd3e32ce 3131 SCMutexLock(&f.m);
997eaf42 3132 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
4a6908d3
AS
3133 request1_2, request1_2_len);
3134 if (r != 0) {
3135 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3136 SCMutexUnlock(&f.m);
4a6908d3
AS
3137 goto end;
3138 }
cd3e32ce 3139 SCMutexUnlock(&f.m);
4a6908d3
AS
3140 if (smtp_state->ts_current_line_db != 1 ||
3141 smtp_state->ts_db == NULL ||
3142 smtp_state->ts_db_len != (int32_t)strlen(request1_str) ||
3143 memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 ||
3144 smtp_state->current_line != smtp_state->ts_db ||
3145 smtp_state->current_line_len != smtp_state->ts_db_len) {
3146 printf("smtp parser in inconsistent state\n");
3147 goto end;
3148 }
3149
cd3e32ce 3150 SCMutexLock(&f.m);
997eaf42 3151 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
4a6908d3
AS
3152 request2, request2_len);
3153 if (r != 0) {
3154 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3155 SCMutexUnlock(&f.m);
4a6908d3
AS
3156 goto end;
3157 }
cd3e32ce 3158 SCMutexUnlock(&f.m);
4a6908d3
AS
3159 if (smtp_state->ts_current_line_db != 0 ||
3160 smtp_state->ts_db != NULL ||
3161 smtp_state->ts_db_len != 0 ||
3162 smtp_state->current_line == NULL ||
3163 smtp_state->current_line_len != (int32_t)strlen(request2_str) ||
3164 memcmp(smtp_state->current_line, request2_str, strlen(request2_str)) != 0) {
3165 printf("smtp parser in inconsistent state\n");
3166 goto end;
3167 }
3168
3169 result = 1;
3170end:
4a6908d3
AS
3171 StreamTcpFreeConfig(TRUE);
3172 FLOW_DESTROY(&f);
997eaf42 3173 SMTPLocalStorageFree(thread_local_data);
4a6908d3
AS
3174 return result;
3175}
3176
3177/*
3178 * \test Test retrieving lines when frag'ed.
3179 */
3180int SMTPParserTest11(void)
3181{
3182 int result = 0;
3183 Flow f;
3184 int r = 0;
3185
3186 const char *request1_str = "";
3187 /* EHLO boo. */
3188 uint8_t request1[] = {
3189 0x0a,
3190 };
3191 int32_t request1_len = sizeof(request1);
3192
3193 const char *request2_str = "EHLO boo.com";
3194 /* EHLO boo.com<CR><LF> */
3195 uint8_t request2[] = {
3196 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3197 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3198 };
3199 int32_t request2_len = sizeof(request2);
3200
3201 TcpSession ssn;
3202
3203 memset(&f, 0, sizeof(f));
3204 memset(&ssn, 0, sizeof(ssn));
3205
3206 FLOW_INITIALIZE(&f);
3207 f.protoctx = (void *)&ssn;
3208
3209 StreamTcpInitConfig(TRUE);
997eaf42 3210 void *thread_local_data = SMTPLocalStorageAlloc();
4a6908d3 3211
cd3e32ce 3212 SCMutexLock(&f.m);
997eaf42 3213 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
4a6908d3
AS
3214 request1, request1_len);
3215 if (r != 0) {
3216 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3217 SCMutexUnlock(&f.m);
4a6908d3
AS
3218 goto end;
3219 }
cd3e32ce 3220 SCMutexUnlock(&f.m);
bf24272c 3221 SMTPState *smtp_state = f.alstate;
4a6908d3
AS
3222 if (smtp_state == NULL) {
3223 printf("no smtp state: ");
3224 goto end;
3225 }
3226 if (smtp_state->current_line == NULL ||
3227 smtp_state->current_line_len != 0 ||
3228 smtp_state->ts_current_line_db == 1 ||
3229 smtp_state->ts_db != NULL ||
3230 smtp_state->ts_db_len != 0 ||
3231 memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) {
3232 printf("smtp parser in inconsistent state\n");
3233 goto end;
3234 }
3235
cd3e32ce 3236 SCMutexLock(&f.m);
997eaf42 3237 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
4a6908d3
AS
3238 request2, request2_len);
3239 if (r != 0) {
3240 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3241 SCMutexUnlock(&f.m);
4a6908d3
AS
3242 goto end;
3243 }
cd3e32ce 3244 SCMutexUnlock(&f.m);
4a6908d3
AS
3245 if (smtp_state->ts_current_line_db != 0 ||
3246 smtp_state->ts_db != NULL ||
3247 smtp_state->ts_db_len != 0 ||
3248 smtp_state->current_line == NULL ||
3249 smtp_state->current_line_len != (int32_t)strlen(request2_str) ||
3250 memcmp(smtp_state->current_line, request2_str, strlen(request2_str)) != 0) {
3251 printf("smtp parser in inconsistent state\n");
3252 goto end;
3253 }
3254
3255 result = 1;
3256end:
4a6908d3
AS
3257 StreamTcpFreeConfig(TRUE);
3258 FLOW_DESTROY(&f);
997eaf42 3259 SMTPLocalStorageFree(thread_local_data);
4a6908d3
AS
3260 return result;
3261}
3262
5311cd48
AS
3263int SMTPParserTest12(void)
3264{
3265 int result = 0;
3266 Signature *s = NULL;
3267 ThreadVars th_v;
3268 Packet *p = NULL;
3269 Flow f;
3270 TcpSession ssn;
3271 DetectEngineThreadCtx *det_ctx = NULL;
3272 DetectEngineCtx *de_ctx = NULL;
3273 SMTPState *smtp_state = NULL;
3274 int r = 0;
3275
3276 /* EHLO boo.com<CR><LF> */
3277 uint8_t request1[] = {
3278 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3279 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3280 };
3281 int32_t request1_len = sizeof(request1);
3282
3283 /* 388<CR><LF>
3284 */
3285 uint8_t reply1[] = {
3286 0x31, 0x38, 0x38, 0x0d, 0x0a,
3287 };
3288 uint32_t reply1_len = sizeof(reply1);
3289
3290 memset(&th_v, 0, sizeof(th_v));
3291 memset(&f, 0, sizeof(f));
3292 memset(&ssn, 0, sizeof(ssn));
3293
3294 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
3295
3296 FLOW_INITIALIZE(&f);
3297 f.protoctx = (void *)&ssn;
3298 p->flow = &f;
3299 p->flowflags |= FLOW_PKT_TOSERVER;
3300 p->flowflags |= FLOW_PKT_ESTABLISHED;
3301 p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
3302 f.alproto = ALPROTO_SMTP;
3303
3304 StreamTcpInitConfig(TRUE);
3305 void *thread_local_data = SMTPLocalStorageAlloc();
3306
3307 de_ctx = DetectEngineCtxInit();
3308 if (de_ctx == NULL)
3309 goto end;
3310
3311 de_ctx->flags |= DE_QUIET;
3312
3313 s = DetectEngineAppendSig(de_ctx,"alert tcp any any -> any any "
3314 "(msg:\"SMTP event handling\"; "
7fa22e84 3315 "app-layer-event: smtp.invalid_reply; "
5311cd48
AS
3316 "sid:1;)");
3317 if (s == NULL)
3318 goto end;
3319
3320 SigGroupBuild(de_ctx);
3321 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
3322
cd3e32ce 3323 SCMutexLock(&f.m);
5311cd48
AS
3324 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER | STREAM_START,
3325 request1, request1_len);
3326 if (r != 0) {
3327 printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
cd3e32ce 3328 SCMutexUnlock(&f.m);
5311cd48
AS
3329 goto end;
3330 }
cd3e32ce 3331 SCMutexUnlock(&f.m);
5311cd48
AS
3332
3333 smtp_state = f.alstate;
3334 if (smtp_state == NULL) {
3335 printf("no smtp state: ");
3336 goto end;
3337 }
3338
3339 /* do detect */
3340 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3341
3342 if (PacketAlertCheck(p, 1)) {
3343 printf("sid 1 matched. It shouldn't match: ");
3344 goto end;
3345 }
3346
cd3e32ce 3347 SCMutexLock(&f.m);
5311cd48
AS
3348 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT | STREAM_TOCLIENT,
3349 reply1, reply1_len);
3350 if (r == 0) {
3351 printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
cd3e32ce 3352 SCMutexUnlock(&f.m);
5311cd48
AS
3353 goto end;
3354 }
cd3e32ce 3355 SCMutexUnlock(&f.m);
5311cd48
AS
3356
3357 /* do detect */
3358 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3359
3360 if (!PacketAlertCheck(p, 1)) {
3361 printf("sid 1 didn't match. Should have matched: ");
3362 goto end;
3363 }
3364
3365 result = 1;
3366
3367end:
3368 SigGroupCleanup(de_ctx);
3369 SigCleanSignatures(de_ctx);
3370
3371 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
3372 DetectEngineCtxFree(de_ctx);
3373
3374 StreamTcpFreeConfig(TRUE);
3375 SMTPLocalStorageFree(thread_local_data);
3376 FLOW_DESTROY(&f);
3377 UTHFreePackets(&p, 1);
3378 return result;
3379}
3380
3381int SMTPParserTest13(void)
3382{
3383 int result = 0;
3384 Signature *s = NULL;
3385 ThreadVars th_v;
3386 Packet *p = NULL;
3387 Flow f;
3388 TcpSession ssn;
3389 DetectEngineThreadCtx *det_ctx = NULL;
3390 DetectEngineCtx *de_ctx = NULL;
3391 SMTPState *smtp_state = NULL;
3392 int r = 0;
3393
3394 /* EHLO boo.com<CR><LF> */
3395 uint8_t request1[] = {
3396 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3397 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3398 };
3399 int32_t request1_len = sizeof(request1);
3400
3401 /* 250<CR><LF>
3402 */
3403 uint8_t reply1[] = {
3404 0x32, 0x35, 0x30, 0x0d, 0x0a,
3405 };
3406 uint32_t reply1_len = sizeof(reply1);
3407
3408 /* MAIL FROM:pbsf@asdfs.com<CR><LF>
3409 * RCPT TO:pbsf@asdfs.com<CR><LF>
3410 * DATA<CR><LF>
3411 * STARTTLS<CR><LF>
3412 */
3413 uint8_t request2[] = {
3414 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
3415 0x4d, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
3416 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
3417 0x0d, 0x0a, 0x52, 0x43, 0x50, 0x54, 0x20, 0x54,
3418 0x4f, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
3419 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
3420 0x0d, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a,
3421 0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
3422 0x0d, 0x0a
3423 };
3424 uint32_t request2_len = sizeof(request2);
3425
3426 memset(&th_v, 0, sizeof(th_v));
3427 memset(&f, 0, sizeof(f));
3428 memset(&ssn, 0, sizeof(ssn));
3429
3430 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
3431
3432 FLOW_INITIALIZE(&f);
3433 f.protoctx = (void *)&ssn;
3434 p->flow = &f;
3435 p->flowflags |= FLOW_PKT_TOSERVER;
3436 p->flowflags |= FLOW_PKT_ESTABLISHED;
3437 p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
3438 f.alproto = ALPROTO_SMTP;
3439
3440 StreamTcpInitConfig(TRUE);
3441 void *thread_local_data = SMTPLocalStorageAlloc();
3442
3443 de_ctx = DetectEngineCtxInit();
3444 if (de_ctx == NULL)
3445 goto end;
3446
3447 de_ctx->flags |= DE_QUIET;
3448
3449 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
3450 "(msg:\"SMTP event handling\"; "
7fa22e84 3451 "app-layer-event: "
5311cd48
AS
3452 "smtp.invalid_pipelined_sequence; "
3453 "sid:1;)");
3454 if (s == NULL)
3455 goto end;
3456
3457 SigGroupBuild(de_ctx);
3458 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
3459
cd3e32ce 3460 SCMutexLock(&f.m);
5311cd48
AS
3461 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER | STREAM_START,
3462 request1, request1_len);
3463 if (r != 0) {
3464 printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
cd3e32ce 3465 SCMutexUnlock(&f.m);
5311cd48
AS
3466 goto end;
3467 }
cd3e32ce 3468 SCMutexUnlock(&f.m);
5311cd48
AS
3469
3470 smtp_state = f.alstate;
3471 if (smtp_state == NULL) {
3472 printf("no smtp state: ");
3473 goto end;
3474 }
3475
3476 /* do detect */
3477 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3478
3479 if (PacketAlertCheck(p, 1)) {
3480 printf("sid 1 matched. It shouldn't match: ");
3481 goto end;
3482 }
3483
cd3e32ce 3484 SCMutexLock(&f.m);
5311cd48
AS
3485 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
3486 reply1, reply1_len);
3487 if (r != 0) {
3488 printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
cd3e32ce 3489 SCMutexUnlock(&f.m);
5311cd48
AS
3490 goto end;
3491 }
cd3e32ce 3492 SCMutexUnlock(&f.m);
5311cd48
AS
3493
3494 /* do detect */
3495 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3496
3497 if (PacketAlertCheck(p, 1)) {
3498 printf("sid 1 matched. It shouldn't match: ");
3499 goto end;
3500 }
3501
cd3e32ce 3502 SCMutexLock(&f.m);
5311cd48
AS
3503 r = AppLayerParse(thread_local_data, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3504 request2, request2_len);
3505 if (r != 0) {
3506 printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
cd3e32ce 3507 SCMutexUnlock(&f.m);
5311cd48
AS
3508 goto end;
3509 }
cd3e32ce 3510 SCMutexUnlock(&f.m);
5311cd48
AS
3511
3512 /* do detect */
3513 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3514
3515 if (!PacketAlertCheck(p, 1)) {
3516 printf("sid 1 didn't match. Should have matched: ");
3517 goto end;
3518 }
3519
3520 result = 1;
3521
3522end:
3523 SigGroupCleanup(de_ctx);
3524 SigCleanSignatures(de_ctx);
3525
3526 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
3527 DetectEngineCtxFree(de_ctx);
3528
3529 StreamTcpFreeConfig(TRUE);
3530 SMTPLocalStorageFree(thread_local_data);
3531 FLOW_DESTROY(&f);
3532 UTHFreePackets(&p, 1);
3533 return result;
3534}
3535
87599bc7
AS
3536#endif /* UNITTESTS */
3537
576ec7da
AS
3538void SMTPParserRegisterTests(void)
3539{
87599bc7 3540#ifdef UNITTESTS
576ec7da
AS
3541 UtRegisterTest("SMTPParserTest01", SMTPParserTest01, 1);
3542 UtRegisterTest("SMTPParserTest02", SMTPParserTest02, 1);
3543 UtRegisterTest("SMTPParserTest03", SMTPParserTest03, 1);
3544 UtRegisterTest("SMTPParserTest04", SMTPParserTest04, 1);
3545 UtRegisterTest("SMTPParserTest05", SMTPParserTest05, 1);
d3ca65de 3546 UtRegisterTest("SMTPParserTest06", SMTPParserTest06, 1);
4a6908d3
AS
3547 UtRegisterTest("SMTPParserTest07", SMTPParserTest07, 1);
3548 UtRegisterTest("SMTPParserTest08", SMTPParserTest08, 1);
3549 UtRegisterTest("SMTPParserTest09", SMTPParserTest09, 1);
3550 UtRegisterTest("SMTPParserTest10", SMTPParserTest10, 1);
3551 UtRegisterTest("SMTPParserTest11", SMTPParserTest11, 1);
5311cd48
AS
3552 UtRegisterTest("SMTPParserTest12", SMTPParserTest12, 1);
3553 UtRegisterTest("SMTPParserTest13", SMTPParserTest13, 1);
87599bc7 3554#endif /* UNITTESTS */
4a6908d3 3555
576ec7da
AS
3556 return;
3557}