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