]> git.ipfire.org Git - people/ms/suricata.git/blame - src/app-layer-smtp.c
app-layer: improve EOF handling
[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
56b74c8b 57#include "util-mem.h"
26ba647d
GL
58#include "util-misc.h"
59
60/* content-limit default value */
61#define FILEDATA_CONTENT_LIMIT 1000
62/* content-inspect-min-size default value */
63#define FILEDATA_CONTENT_INSPECT_MIN_SIZE 1000
64/* content-inspect-window default value */
65#define FILEDATA_CONTENT_INSPECT_WINDOW 1000
56b74c8b 66
576ec7da
AS
67#define SMTP_MAX_REQUEST_AND_REPLY_LINE_LENGTH 510
68
69#define SMTP_COMMAND_BUFFER_STEPS 5
70
71/* we are in process of parsing a fresh command. Just a placeholder. If we
72 * are not in STATE_COMMAND_DATA_MODE, we have to be in this mode */
73#define SMTP_PARSER_STATE_COMMAND_MODE 0x00
74/* we are in mode of parsing a command's data. Used when we are parsing tls
75 * or accepting the rfc 2822 mail after DATA command */
76#define SMTP_PARSER_STATE_COMMAND_DATA_MODE 0x01
77/* Used when we are still in the process of parsing a server command. Used
78 * with multi-line replies and the stream is fragmented before all the lines
79 * for a response is seen */
80#define SMTP_PARSER_STATE_PARSING_SERVER_RESPONSE 0x02
81/* Used to indicate that the parser has seen the first reply */
82#define SMTP_PARSER_STATE_FIRST_REPLY_SEEN 0x04
83/* Used to indicate that the parser is parsing a multiline reply */
84#define SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY 0x08
85
86/* Various SMTP commands
87 * We currently have var-ified just STARTTLS and DATA, since we need to them
88 * for state transitions. The rest are just indicate as OTHER_CMD. Other
89 * commands would be introduced as and when needed */
90#define SMTP_COMMAND_STARTTLS 1
91#define SMTP_COMMAND_DATA 2
d3ca65de 92#define SMTP_COMMAND_BDAT 3
576ec7da
AS
93/* not an actual command per se, but the mode where we accept the mail after
94 * DATA has it's own reply code for completion, from the server. We give this
95 * stage a pseudo command of it's own, so that we can add this to the command
96 * buffer to match with the reply */
d3ca65de 97#define SMTP_COMMAND_DATA_MODE 4
576ec7da 98/* All other commands are represented by this var */
d3ca65de 99#define SMTP_COMMAND_OTHER_CMD 5
576ec7da
AS
100
101/* Different EHLO extensions. Not used now. */
102#define SMTP_EHLO_EXTENSION_PIPELINING
103#define SMTP_EHLO_EXTENSION_SIZE
104#define SMTP_EHLO_EXTENSION_DSN
105#define SMTP_EHLO_EXTENSION_STARTTLS
106#define SMTP_EHLO_EXTENSION_8BITMIME
107
5311cd48
AS
108SCEnumCharMap smtp_decoder_event_table[ ] = {
109 { "INVALID_REPLY", SMTP_DECODER_EVENT_INVALID_REPLY },
110 { "UNABLE_TO_MATCH_REPLY_WITH_REQUEST",
111 SMTP_DECODER_EVENT_UNABLE_TO_MATCH_REPLY_WITH_REQUEST },
112 { "MAX_COMMAND_LINE_LEN_EXCEEDED",
113 SMTP_DECODER_EVENT_MAX_COMMAND_LINE_LEN_EXCEEDED },
114 { "MAX_REPLY_LINE_LEN_EXCEEDED",
115 SMTP_DECODER_EVENT_MAX_REPLY_LINE_LEN_EXCEEDED },
116 { "INVALID_PIPELINED_SEQUENCE",
117 SMTP_DECODER_EVENT_INVALID_PIPELINED_SEQUENCE },
118 { "BDAT_CHUNK_LEN_EXCEEDED",
119 SMTP_DECODER_EVENT_BDAT_CHUNK_LEN_EXCEEDED },
120 { "NO_SERVER_WELCOME_MESSAGE",
121 SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE },
122 { "TLS_REJECTED",
123 SMTP_DECODER_EVENT_TLS_REJECTED },
124 { "DATA_COMMAND_REJECTED",
125 SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED },
c2dc6867
DA
126
127 /* MIME Events */
128 { "MIME_PARSE_FAILED",
129 SMTP_DECODER_EVENT_MIME_PARSE_FAILED },
130 { "MIME_MALFORMED_MSG",
131 SMTP_DECODER_EVENT_MIME_MALFORMED_MSG },
132 { "MIME_INVALID_BASE64",
133 SMTP_DECODER_EVENT_MIME_INVALID_BASE64 },
134 { "MIME_INVALID_QP",
135 SMTP_DECODER_EVENT_MIME_INVALID_QP },
136 { "MIME_LONG_LINE",
137 SMTP_DECODER_EVENT_MIME_LONG_LINE },
138 { "MIME_LONG_ENC_LINE",
139 SMTP_DECODER_EVENT_MIME_LONG_ENC_LINE },
140 { "MIME_LONG_HEADER_NAME",
141 SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME },
142 { "MIME_LONG_HEADER_VALUE",
143 SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE },
6d170cad
VJ
144 { "MIME_LONG_BOUNDARY",
145 SMTP_DECODER_EVENT_MIME_BOUNDARY_TOO_LONG },
c2dc6867 146
5311cd48
AS
147 { NULL, -1 },
148};
4d38a571 149
e05034f5 150#define SMTP_MPM DEFAULT_MPM
4d38a571
AS
151
152static MpmCtx *smtp_mpm_ctx = NULL;
153MpmThreadCtx *smtp_mpm_thread_ctx;
154
155/* smtp reply codes. If an entry is made here, please make a simultaneous
156 * entry in smtp_reply_map */
157enum {
158 SMTP_REPLY_211,
159 SMTP_REPLY_214,
160 SMTP_REPLY_220,
161 SMTP_REPLY_221,
7850d896 162 SMTP_REPLY_235,
4d38a571
AS
163 SMTP_REPLY_250,
164 SMTP_REPLY_251,
165 SMTP_REPLY_252,
166
7850d896 167 SMTP_REPLY_334,
4d38a571
AS
168 SMTP_REPLY_354,
169
170 SMTP_REPLY_421,
171 SMTP_REPLY_450,
172 SMTP_REPLY_451,
173 SMTP_REPLY_452,
174 SMTP_REPLY_455,
175
176 SMTP_REPLY_500,
177 SMTP_REPLY_501,
178 SMTP_REPLY_502,
179 SMTP_REPLY_503,
180 SMTP_REPLY_504,
181 SMTP_REPLY_550,
182 SMTP_REPLY_551,
183 SMTP_REPLY_552,
184 SMTP_REPLY_553,
185 SMTP_REPLY_554,
186 SMTP_REPLY_555,
187};
188
189SCEnumCharMap smtp_reply_map[ ] = {
190 { "211", SMTP_REPLY_211 },
191 { "214", SMTP_REPLY_214 },
192 { "220", SMTP_REPLY_220 },
193 { "221", SMTP_REPLY_221 },
7850d896 194 { "235", SMTP_REPLY_235 },
4d38a571
AS
195 { "250", SMTP_REPLY_250 },
196 { "251", SMTP_REPLY_251 },
197 { "252", SMTP_REPLY_252 },
198
7850d896 199 { "334", SMTP_REPLY_334 },
4d38a571
AS
200 { "354", SMTP_REPLY_354 },
201
202 { "421", SMTP_REPLY_421 },
203 { "450", SMTP_REPLY_450 },
204 { "451", SMTP_REPLY_451 },
205 { "452", SMTP_REPLY_452 },
206 { "455", SMTP_REPLY_455 },
207
208 { "500", SMTP_REPLY_500 },
209 { "501", SMTP_REPLY_501 },
210 { "502", SMTP_REPLY_502 },
211 { "503", SMTP_REPLY_503 },
212 { "504", SMTP_REPLY_504 },
213 { "550", SMTP_REPLY_550 },
214 { "551", SMTP_REPLY_551 },
215 { "552", SMTP_REPLY_552 },
216 { "553", SMTP_REPLY_553 },
217 { "554", SMTP_REPLY_554 },
218 { "555", SMTP_REPLY_555 },
219 { NULL, -1 },
220};
c2dc6867 221
c2dc6867 222/* Create SMTP config structure */
26ba647d 223SMTPConfig smtp_config = { 0, { 0, 0, 0, 0 }, 0, 0, 0};
c2dc6867
DA
224
225/**
e5c36952 226 * \brief Configure SMTP Mime Decoder by parsing out mime section of YAML
c2dc6867
DA
227 * config file
228 *
229 * \return none
230 */
231static void SMTPConfigure(void) {
232
233 SCEnter();
234 int ret = 0, val;
235 intmax_t imval;
26ba647d
GL
236 uint32_t content_limit = 0;
237 uint32_t content_inspect_min_size = 0;
238 uint32_t content_inspect_window = 0;
c2dc6867 239
e5c36952 240 ConfNode *config = ConfGetNode("app-layer.protocols.smtp.mime");
c2dc6867
DA
241 if (config != NULL) {
242
243 ret = ConfGetChildValueBool(config, "decode-mime", &val);
244 if (ret) {
245 smtp_config.decode_mime = val;
246 }
247
248 ret = ConfGetChildValueBool(config, "decode-base64", &val);
249 if (ret) {
250 smtp_config.mime_config.decode_base64 = val;
251 }
252
253 ret = ConfGetChildValueBool(config, "decode-quoted-printable", &val);
254 if (ret) {
255 smtp_config.mime_config.decode_quoted_printable = val;
256 }
257
258 ret = ConfGetChildValueInt(config, "header-value-depth", &imval);
259 if (ret) {
260 smtp_config.mime_config.header_value_depth = (uint32_t) imval;
261 }
262
263 ret = ConfGetChildValueBool(config, "extract-urls", &val);
264 if (ret) {
265 smtp_config.mime_config.extract_urls = val;
266 }
267 }
268
269 /* Pass mime config data to MimeDec API */
270 MimeDecSetConfig(&smtp_config.mime_config);
271
26ba647d
GL
272 ConfNode *t = ConfGetNode("app-layer.protocols.smtp.inspected-tracker");
273 ConfNode *p = NULL;
274
275 if (t == NULL)
276 return;
277
278 TAILQ_FOREACH(p, &t->head, next) {
279 if (strcasecmp("content-limit", p->name) == 0) {
280 if (ParseSizeStringU32(p->val, &content_limit) < 0) {
281 SCLogWarning(SC_ERR_SIZE_PARSE, "Error parsing content-limit "
282 "from conf file - %s. Killing engine", p->val);
283 content_limit = FILEDATA_CONTENT_LIMIT;
284 }
285 }
286
287 if (strcasecmp("content-inspect-min-size", p->name) == 0) {
288 if (ParseSizeStringU32(p->val, &content_inspect_min_size) < 0) {
289 SCLogWarning(SC_ERR_SIZE_PARSE, "Error parsing content-inspect-min-size-limit "
290 "from conf file - %s. Killing engine", p->val);
291 content_inspect_min_size = FILEDATA_CONTENT_INSPECT_MIN_SIZE;
292 }
293 }
294
295 if (strcasecmp("content-inspect-window", p->name) == 0) {
296 if (ParseSizeStringU32(p->val, &content_inspect_window) < 0) {
297 SCLogWarning(SC_ERR_SIZE_PARSE, "Error parsing content-inspect-window "
298 "from conf file - %s. Killing engine", p->val);
299 content_inspect_window = FILEDATA_CONTENT_INSPECT_WINDOW;
300 }
301 }
302 }
303
c2dc6867
DA
304 SCReturn;
305}
306
d209699a
VJ
307void SMTPSetEvent(SMTPState *s, uint8_t e)
308{
309 SCLogDebug("setting event %u", e);
310
311 if (s->curr_tx != NULL) {
312 AppLayerDecoderEventsSetEventRaw(&s->curr_tx->decoder_events, e);
313// s->events++;
314 return;
315 }
316 SCLogDebug("couldn't set event %u", e);
317}
318
56b74c8b
VJ
319static SMTPTransaction *SMTPTransactionCreate(void)
320{
321 SMTPTransaction *tx = SCCalloc(1, sizeof(*tx));
322 if (tx == NULL) {
323 return NULL;
324 }
325
326 tx->mime_state = NULL;
327 return tx;
328}
329
d2657bec 330int SMTPProcessDataChunk(const uint8_t *chunk, uint32_t len,
c2dc6867
DA
331 MimeDecParseState *state) {
332
333 int ret = MIME_DEC_OK;
334 Flow *flow = (Flow *) state->data;
335 SMTPState *smtp_state = (SMTPState *) flow->alstate;
336 MimeDecEntity *entity = (MimeDecEntity *) state->stack->top->data;
337 FileContainer *files = NULL;
338 uint16_t flags = 0;
339
340 /* Set flags */
341 if (flow->flags & FLOW_FILE_NO_STORE_TS) {
342 flags |= FILE_NOSTORE;
343 }
344
345 if (flow->flags & FLOW_FILE_NO_MAGIC_TS) {
346 flags |= FILE_NOMAGIC;
347 }
348
349 if (flow->flags & FLOW_FILE_NO_MD5_TS) {
350 flags |= FILE_NOMD5;
351 }
352
353 /* Determine whether to process files */
354 if ((flags & (FILE_NOSTORE | FILE_NOMAGIC | FILE_NOMD5)) ==
355 (FILE_NOSTORE | FILE_NOMAGIC | FILE_NOMD5)) {
356 SCLogDebug("File content ignored");
357 return 0;
358 }
359
360 /* Find file */
361 if (entity->ctnt_flags & CTNT_IS_ATTACHMENT) {
362
363 /* Make sure file container allocated */
364 if (smtp_state->files_ts == NULL) {
365 smtp_state->files_ts = FileContainerAlloc();
366 if (smtp_state->files_ts == NULL) {
367 ret = MIME_DEC_ERR_MEM;
368 SCLogError(SC_ERR_MEM_ALLOC, "Could not create file container");
369 goto end;
370 }
371 }
372 files = smtp_state->files_ts;
373
374 /* Open file if necessary */
375 if (state->body_begin) {
376
377 if (SCLogDebugEnabled()) {
378 SCLogDebug("Opening file...%u bytes", len);
379 printf("File - ");
380 for (uint32_t i = 0; i < entity->filename_len; i++) {
381 printf("%c", entity->filename[i]);
382 }
383 printf("\n");
384 }
385
386 /* Set storage flag if applicable since only the first file in the
387 * flow seems to be processed by the 'filestore' detector */
388 if (files->head != NULL && (files->head->flags & FILE_STORE)) {
389 flags |= FILE_STORE;
390 }
391
392 if (FileOpenFile(files, (uint8_t *) entity->filename, entity->filename_len,
393 (uint8_t *) chunk, len, flags) == NULL) {
394 ret = MIME_DEC_ERR_DATA;
395 SCLogDebug("FileOpenFile() failed");
396 }
397
398 /* If close in the same chunk, then pass in empty bytes */
399 if (state->body_end) {
400
401 SCLogDebug("Closing file...%u bytes", len);
402
403 if (files->tail->state == FILE_STATE_OPENED) {
404 ret = FileCloseFile(files, (uint8_t *) NULL, 0, flags);
405 if (ret != 0) {
406 SCLogDebug("FileCloseFile() failed: %d", ret);
9d33131d 407 ret = MIME_DEC_ERR_DATA;
c2dc6867
DA
408 }
409 } else {
410 SCLogDebug("File already closed");
411 }
412 }
413 } else if (state->body_end) {
414 /* Close file */
415 SCLogDebug("Closing file...%u bytes", len);
416
56b74c8b 417 if (files && files->tail && files->tail->state == FILE_STATE_OPENED) {
c2dc6867
DA
418 ret = FileCloseFile(files, (uint8_t *) chunk, len, flags);
419 if (ret != 0) {
420 SCLogDebug("FileCloseFile() failed: %d", ret);
9d33131d 421 ret = MIME_DEC_ERR_DATA;
c2dc6867
DA
422 }
423 } else {
424 SCLogDebug("File already closed");
425 }
426 } else {
427 /* Append data chunk to file */
428 SCLogDebug("Appending file...%u bytes", len);
429
430 /* 0 is ok, -2 is not stored, -1 is error */
431 ret = FileAppendData(files, (uint8_t *) chunk, len);
432 if (ret == -2) {
433 ret = 0;
434 SCLogDebug("FileAppendData() - file no longer being extracted");
435 } else if (ret < 0) {
436 SCLogDebug("FileAppendData() failed: %d", ret);
9d33131d 437 ret = MIME_DEC_ERR_DATA;
c2dc6867
DA
438 }
439 }
440
9d33131d 441 if (ret == 0) {
c2dc6867
DA
442 SCLogDebug("Successfully processed file data!");
443 }
444 } else {
445 SCLogDebug("Body not a Ctnt_attachment");
446 }
447
448 if (files != NULL) {
449 FilePrune(files);
450 }
451end:
452 SCReturnInt(ret);
453}
576ec7da
AS
454
455/**
456 * \internal
457 * \brief Get the next line from input. It doesn't do any length validation.
458 *
459 * \param state The smtp state.
460 *
461 * \retval 0 On suceess.
462 * \retval -1 Either when we don't have any new lines to supply anymore or
463 * on failure.
464 */
465static int SMTPGetLine(SMTPState *state)
466{
7b0f261f 467 SCEnter();
1f07d152 468 void *ptmp;
7b0f261f 469
88115902
AS
470 /* we have run out of input */
471 if (state->input_len <= 0)
576ec7da
AS
472 return -1;
473
88115902
AS
474 /* toserver */
475 if (state->direction == 0) {
476 if (state->ts_current_line_lf_seen == 1) {
477 /* we have seen the lf for the previous line. Clear the parser
478 * details to parse new line */
479 state->ts_current_line_lf_seen = 0;
480 if (state->ts_current_line_db == 1) {
481 state->ts_current_line_db = 0;
482 SCFree(state->ts_db);
483 state->ts_db = NULL;
4a6908d3 484 state->ts_db_len = 0;
88115902 485 state->current_line = NULL;
4a6908d3 486 state->current_line_len = 0;
88115902 487 }
576ec7da 488 }
576ec7da 489
88115902 490 uint8_t *lf_idx = memchr(state->input, 0x0a, state->input_len);
576ec7da 491
88115902 492 if (lf_idx == NULL) {
5311cd48
AS
493 /* fragmented lines. Decoder event for special cases. Not all
494 * fragmented lines should be treated as a possible evasion
495 * attempt. With multi payload smtp chunks we can have valid
496 * cases of fragmentation. But within the same segment chunk
497 * if we see fragmentation then it's definitely something you
498 * should alert about */
88115902 499 if (state->ts_current_line_db == 0) {
88115902
AS
500 state->ts_db = SCMalloc(state->input_len);
501 if (state->ts_db == NULL) {
502 return -1;
503 }
4a6908d3 504 state->ts_current_line_db = 1;
88115902
AS
505 memcpy(state->ts_db, state->input, state->input_len);
506 state->ts_db_len = state->input_len;
507 } else {
1f07d152
EL
508 ptmp = SCRealloc(state->ts_db,
509 (state->ts_db_len + state->input_len));
510 if (ptmp == NULL) {
511 SCFree(state->ts_db);
512 state->ts_db = NULL;
513 state->ts_db_len = 0;
88115902
AS
514 return -1;
515 }
1f07d152
EL
516 state->ts_db = ptmp;
517
88115902
AS
518 memcpy(state->ts_db + state->ts_db_len,
519 state->input, state->input_len);
520 state->ts_db_len += state->input_len;
521 } /* else */
522 state->input += state->input_len;
523 state->input_len = 0;
524
525 return -1;
4a6908d3 526
576ec7da 527 } else {
88115902
AS
528 state->ts_current_line_lf_seen = 1;
529
4a6908d3 530 if (state->ts_current_line_db == 1) {
1f07d152
EL
531 ptmp = SCRealloc(state->ts_db,
532 (state->ts_db_len + (lf_idx + 1 - state->input)));
533 if (ptmp == NULL) {
534 SCFree(state->ts_db);
535 state->ts_db = NULL;
536 state->ts_db_len = 0;
4a6908d3
AS
537 return -1;
538 }
1f07d152
EL
539 state->ts_db = ptmp;
540
4a6908d3
AS
541 memcpy(state->ts_db + state->ts_db_len,
542 state->input, (lf_idx + 1 - state->input));
543 state->ts_db_len += (lf_idx + 1 - state->input);
544
545 if (state->ts_db_len > 1 &&
546 state->ts_db[state->ts_db_len - 2] == 0x0D) {
547 state->ts_db_len -= 2;
548 state->current_line_delimiter_len = 2;
88115902 549 } else {
4a6908d3
AS
550 state->ts_db_len -= 1;
551 state->current_line_delimiter_len = 1;
88115902 552 }
576ec7da 553
4a6908d3
AS
554 state->current_line = state->ts_db;
555 state->current_line_len = state->ts_db_len;
556
88115902 557 } else {
4a6908d3
AS
558 state->current_line = state->input;
559 state->current_line_len = lf_idx - state->input;
560
561 if (state->input != lf_idx &&
562 *(lf_idx - 1) == 0x0D) {
563 state->current_line_len--;
564 state->current_line_delimiter_len = 2;
88115902 565 } else {
4a6908d3 566 state->current_line_delimiter_len = 1;
88115902 567 }
4a6908d3 568 }
88115902
AS
569
570 state->input_len -= (lf_idx - state->input) + 1;
4a6908d3 571 state->input = (lf_idx + 1);
88115902
AS
572
573 return 0;
4a6908d3 574 }
88115902
AS
575
576 /* toclient */
576ec7da 577 } else {
88115902
AS
578 if (state->tc_current_line_lf_seen == 1) {
579 /* we have seen the lf for the previous line. Clear the parser
580 * details to parse new line */
581 state->tc_current_line_lf_seen = 0;
582 if (state->tc_current_line_db == 1) {
583 state->tc_current_line_db = 0;
584 SCFree(state->tc_db);
585 state->tc_db = NULL;
4a6908d3 586 state->tc_db_len = 0;
88115902 587 state->current_line = NULL;
4a6908d3 588 state->current_line_len = 0;
88115902
AS
589 }
590 }
591
592 uint8_t *lf_idx = memchr(state->input, 0x0a, state->input_len);
593
594 if (lf_idx == NULL) {
5311cd48
AS
595 /* fragmented lines. Decoder event for special cases. Not all
596 * fragmented lines should be treated as a possible evasion
597 * attempt. With multi payload smtp chunks we can have valid
598 * cases of fragmentation. But within the same segment chunk
599 * if we see fragmentation then it's definitely something you
600 * should alert about */
88115902 601 if (state->tc_current_line_db == 0) {
88115902
AS
602 state->tc_db = SCMalloc(state->input_len);
603 if (state->tc_db == NULL) {
576ec7da
AS
604 return -1;
605 }
4a6908d3 606 state->tc_current_line_db = 1;
88115902
AS
607 memcpy(state->tc_db, state->input, state->input_len);
608 state->tc_db_len = state->input_len;
576ec7da 609 } else {
1f07d152
EL
610 ptmp = SCRealloc(state->tc_db,
611 (state->tc_db_len + state->input_len));
612 if (ptmp == NULL) {
613 SCFree(state->tc_db);
614 state->tc_db = NULL;
615 state->tc_db_len = 0;
88115902
AS
616 return -1;
617 }
1f07d152
EL
618 state->tc_db = ptmp;
619
88115902
AS
620 memcpy(state->tc_db + state->tc_db_len,
621 state->input, state->input_len);
622 state->tc_db_len += state->input_len;
623 } /* else */
624 state->input += state->input_len;
625 state->input_len = 0;
576ec7da 626
88115902 627 return -1;
4a6908d3 628
576ec7da 629 } else {
88115902
AS
630 state->tc_current_line_lf_seen = 1;
631
4a6908d3 632 if (state->tc_current_line_db == 1) {
1f07d152
EL
633 ptmp = SCRealloc(state->tc_db,
634 (state->tc_db_len + (lf_idx + 1 - state->input)));
635 if (ptmp == NULL) {
636 SCFree(state->tc_db);
637 state->tc_db = NULL;
638 state->tc_db_len = 0;
4a6908d3
AS
639 return -1;
640 }
1f07d152
EL
641 state->tc_db = ptmp;
642
4a6908d3
AS
643 memcpy(state->tc_db + state->tc_db_len,
644 state->input, (lf_idx + 1 - state->input));
645 state->tc_db_len += (lf_idx + 1 - state->input);
646
647 if (state->tc_db_len > 1 &&
648 state->tc_db[state->tc_db_len - 2] == 0x0D) {
649 state->tc_db_len -= 2;
650 state->current_line_delimiter_len = 2;
88115902 651 } else {
4a6908d3
AS
652 state->tc_db_len -= 1;
653 state->current_line_delimiter_len = 1;
576ec7da 654 }
88115902 655
4a6908d3
AS
656 state->current_line = state->tc_db;
657 state->current_line_len = state->tc_db_len;
658
576ec7da 659 } else {
4a6908d3
AS
660 state->current_line = state->input;
661 state->current_line_len = lf_idx - state->input;
662
663 if (state->input != lf_idx &&
664 *(lf_idx - 1) == 0x0D) {
665 state->current_line_len--;
666 state->current_line_delimiter_len = 2;
88115902 667 } else {
4a6908d3 668 state->current_line_delimiter_len = 1;
88115902 669 }
4a6908d3 670 }
576ec7da 671
88115902 672 state->input_len -= (lf_idx - state->input) + 1;
4a6908d3 673 state->input = (lf_idx + 1);
88115902
AS
674
675 return 0;
676 } /* else - if (lf_idx == NULL) */
677 }
576ec7da 678
576ec7da
AS
679}
680
5311cd48 681static int SMTPInsertCommandIntoCommandBuffer(uint8_t command, SMTPState *state, Flow *f)
576ec7da 682{
7b0f261f 683 SCEnter();
1f07d152 684 void *ptmp;
7b0f261f 685
576ec7da 686 if (state->cmds_cnt >= state->cmds_buffer_len) {
bc5c9f4a
VJ
687 int increment = SMTP_COMMAND_BUFFER_STEPS;
688 if ((int)(state->cmds_buffer_len + SMTP_COMMAND_BUFFER_STEPS) > (int)USHRT_MAX) {
689 increment = USHRT_MAX - state->cmds_buffer_len;
690 }
691
1f07d152
EL
692 ptmp = SCRealloc(state->cmds,
693 sizeof(uint8_t) * (state->cmds_buffer_len + increment));
694 if (ptmp == NULL) {
695 SCFree(state->cmds);
696 state->cmds = NULL;
697 SCLogDebug("SCRealloc failure");
576ec7da
AS
698 return -1;
699 }
1f07d152
EL
700 state->cmds = ptmp;
701
bc5c9f4a 702 state->cmds_buffer_len += increment;
576ec7da
AS
703 }
704 if (state->cmds_cnt >= 1 &&
705 ((state->cmds[state->cmds_cnt - 1] == SMTP_COMMAND_STARTTLS) ||
706 (state->cmds[state->cmds_cnt - 1] == SMTP_COMMAND_DATA))) {
707 /* decoder event */
d209699a 708 SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_PIPELINED_SEQUENCE);
576ec7da
AS
709 /* we have to have EHLO, DATA, VRFY, EXPN, TURN, QUIT, NOOP,
710 * STARTTLS as the last command in pipelined mode */
711 }
bc5c9f4a
VJ
712
713 /** \todo decoder event */
7b0f261f
VJ
714 if ((int)(state->cmds_cnt + 1) > (int)USHRT_MAX) {
715 SCLogDebug("command buffer overflow");
bc5c9f4a 716 return -1;
7b0f261f 717 }
bc5c9f4a 718
576ec7da
AS
719 state->cmds[state->cmds_cnt] = command;
720 state->cmds_cnt++;
721
722 return 0;
723}
724
d3ca65de 725static int SMTPProcessCommandBDAT(SMTPState *state, Flow *f,
9634e60e 726 AppLayerParserState *pstate)
d3ca65de 727{
7b0f261f
VJ
728 SCEnter();
729
d3ca65de
AS
730 state->bdat_chunk_idx += (state->current_line_len +
731 state->current_line_delimiter_len);
732 if (state->bdat_chunk_idx > state->bdat_chunk_len) {
733 state->parser_state &= ~SMTP_PARSER_STATE_COMMAND_DATA_MODE;
734 /* decoder event */
d209699a 735 SMTPSetEvent(state, SMTP_DECODER_EVENT_BDAT_CHUNK_LEN_EXCEEDED);
7b0f261f 736 SCReturnInt(-1);
d3ca65de
AS
737 } else if (state->bdat_chunk_idx == state->bdat_chunk_len) {
738 state->parser_state &= ~SMTP_PARSER_STATE_COMMAND_DATA_MODE;
739 }
740
7b0f261f 741 SCReturnInt(0);
d3ca65de
AS
742}
743
576ec7da 744static int SMTPProcessCommandDATA(SMTPState *state, Flow *f,
9634e60e 745 AppLayerParserState *pstate)
576ec7da 746{
7b0f261f
VJ
747 SCEnter();
748
576ec7da
AS
749 if (!(state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
750 /* looks like are still waiting for a confirmination from the server */
751 return 0;
752 }
753
754 if (state->current_line_len == 1 && state->current_line[0] == '.') {
755 state->parser_state &= ~SMTP_PARSER_STATE_COMMAND_DATA_MODE;
756 /* kinda like a hack. The mail sent in DATA mode, would be
757 * acknowledged with a reply. We insert a dummy command to
758 * the command buffer to be used by the reply handler to match
759 * the reply received */
5311cd48 760 SMTPInsertCommandIntoCommandBuffer(SMTP_COMMAND_DATA_MODE, state, f);
c2dc6867
DA
761
762 if (smtp_config.decode_mime) {
763 /* Complete parsing task */
56b74c8b 764 int ret = MimeDecParseComplete(state->curr_tx->mime_state);
c2dc6867
DA
765 if (ret != MIME_DEC_OK) {
766
d209699a 767 SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_PARSE_FAILED);
c2dc6867
DA
768 SCLogDebug("MimeDecParseComplete() function failed");
769 }
770
771 /* Generate decoder events */
56b74c8b 772 MimeDecEntity *msg = state->curr_tx->mime_state->msg;
c2dc6867 773 if (msg->anomaly_flags & ANOM_INVALID_BASE64) {
d209699a 774 SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_INVALID_BASE64);
c2dc6867
DA
775 }
776 if (msg->anomaly_flags & ANOM_INVALID_QP) {
d209699a 777 SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_INVALID_QP);
c2dc6867
DA
778 }
779 if (msg->anomaly_flags & ANOM_LONG_LINE) {
d209699a 780 SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_LINE);
c2dc6867
DA
781 }
782 if (msg->anomaly_flags & ANOM_LONG_ENC_LINE) {
d209699a 783 SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_ENC_LINE);
c2dc6867
DA
784 }
785 if (msg->anomaly_flags & ANOM_LONG_HEADER_NAME) {
d209699a 786 SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME);
c2dc6867
DA
787 }
788 if (msg->anomaly_flags & ANOM_LONG_HEADER_VALUE) {
d209699a 789 SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE);
c2dc6867
DA
790 }
791 if (msg->anomaly_flags & ANOM_MALFORMED_MSG) {
d209699a 792 SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_MALFORMED_MSG);
c2dc6867 793 }
6d170cad
VJ
794 if (msg->anomaly_flags & ANOM_LONG_BOUNDARY) {
795 SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_BOUNDARY_TOO_LONG);
796 }
c2dc6867 797 }
d209699a
VJ
798 state->curr_tx->done = 1;
799 SCLogDebug("marked tx as done");
c2dc6867
DA
800 }
801
802 /* If DATA, then parse out a MIME message */
803 if (state->current_command == SMTP_COMMAND_DATA &&
804 (state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
805
d209699a 806 if (smtp_config.decode_mime && state->curr_tx->mime_state) {
106bbc78 807 int ret = MimeDecParseLine((const uint8_t *) state->current_line,
56b74c8b 808 state->current_line_len, state->curr_tx->mime_state);
c2dc6867
DA
809 if (ret != MIME_DEC_OK) {
810 SCLogDebug("MimeDecParseLine() function returned an error code: %d", ret);
811 }
812 }
576ec7da
AS
813 }
814
815 return 0;
816}
817
818static int SMTPProcessCommandSTARTTLS(SMTPState *state, Flow *f,
9634e60e 819 AppLayerParserState *pstate)
576ec7da
AS
820{
821 return 0;
822}
823
824static int SMTPProcessReply(SMTPState *state, Flow *f,
9634e60e 825 AppLayerParserState *pstate)
576ec7da 826{
7b0f261f
VJ
827 SCEnter();
828
576ec7da 829 uint64_t reply_code = 0;
997eaf42 830 PatternMatcherQueue *pmq = state->thread_local_data;
576ec7da 831
576ec7da
AS
832 /* the reply code has to contain at least 3 bytes, to hold the 3 digit
833 * reply code */
834 if (state->current_line_len < 3) {
835 /* decoder event */
d209699a 836 SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY);
576ec7da
AS
837 return -1;
838 }
839
840 if (state->current_line_len >= 4) {
841 if (state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY) {
842 if (state->current_line[3] != '-') {
843 state->parser_state &= ~SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY;
844 }
845 } else {
846 if (state->current_line[3] == '-') {
847 state->parser_state |= SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY;
848 }
849 }
850 } else {
851 if (state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY) {
852 state->parser_state &= ~SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY;
853 }
854 }
855
4d38a571
AS
856 /* I don't like this pmq reset here. We'll devise a method later, that
857 * should make the use of the mpm very efficient */
997eaf42 858 PmqReset(pmq);
4d38a571 859 int mpm_cnt = mpm_table[SMTP_MPM].Search(smtp_mpm_ctx, smtp_mpm_thread_ctx,
997eaf42 860 pmq, state->current_line,
4d38a571
AS
861 3);
862 if (mpm_cnt == 0) {
863 /* set decoder event - reply code invalid */
d209699a 864 SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY);
7b0f261f
VJ
865 SCLogDebug("invalid reply code %02x %02x %02x",
866 state->current_line[0], state->current_line[1], state->current_line[2]);
867 SCReturnInt(-1);
4d38a571 868 }
997eaf42 869 reply_code = smtp_reply_map[pmq->pattern_id_array[0]].enum_value;
4d38a571
AS
870
871 if (state->cmds_idx == state->cmds_cnt) {
0d7159b5
AS
872 if (!(state->parser_state & SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
873 state->parser_state |= SMTP_PARSER_STATE_FIRST_REPLY_SEEN;
874 if (reply_code == SMTP_REPLY_220)
875 SCReturnInt(0);
876 else
d209699a 877 SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY);
4d38a571 878 } else {
0d7159b5
AS
879 /* decoder event - unable to match reply with request */
880 SCLogDebug("unable to match reply with request");
881 SCReturnInt(-1);
576ec7da
AS
882 }
883 }
884
95fa5ae1
VJ
885 if (state->cmds_cnt == 0) {
886 /* reply but not a command we have stored, fall through */
887 } else if (state->cmds[state->cmds_idx] == SMTP_COMMAND_STARTTLS) {
4d38a571 888 if (reply_code == SMTP_REPLY_220) {
576ec7da
AS
889 /* we are entering STARRTTLS data mode */
890 state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE;
8527b8e0 891 AppLayerParserStateSetFlag(pstate,
429c6388
AS
892 APP_LAYER_PARSER_NO_INSPECTION |
893 APP_LAYER_PARSER_NO_REASSEMBLY);
576ec7da
AS
894 } else {
895 /* decoder event */
d209699a 896 SMTPSetEvent(state, SMTP_DECODER_EVENT_TLS_REJECTED);
576ec7da
AS
897 }
898 } else if (state->cmds[state->cmds_idx] == SMTP_COMMAND_DATA) {
4d38a571 899 if (reply_code == SMTP_REPLY_354) {
576ec7da
AS
900 /* Next comes the mail for the DATA command in toserver direction */
901 state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE;
902 } else {
903 /* decoder event */
d209699a 904 SMTPSetEvent(state, SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED);
576ec7da
AS
905 }
906 } else {
4d38a571
AS
907 /* we don't care for any other command for now */
908 /* check if reply falls in the valid list of replies for SMTP. If not
909 * decoder event */
576ec7da
AS
910 }
911
4d38a571 912 /* if it is a multi-line reply, we need to move the index only once for all
576ec7da
AS
913 * the line of the reply. We unset the multiline flag on the last
914 * line of the multiline reply, following which we increment the index */
915 if (!(state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY)) {
916 state->cmds_idx++;
917 }
918
919 /* if we have matched all the buffered commands, reset the cnt and index */
920 if (state->cmds_idx == state->cmds_cnt) {
921 state->cmds_cnt = 0;
922 state->cmds_idx = 0;
923 }
924
925 return 0;
926}
927
d3ca65de
AS
928static int SMTPParseCommandBDAT(SMTPState *state)
929{
7b0f261f
VJ
930 SCEnter();
931
d3ca65de
AS
932 int i = 4;
933 while (i < state->current_line_len) {
934 if (state->current_line[i] != ' ') {
935 break;
936 }
937 i++;
938 }
939 if (i == 4) {
940 /* decoder event */
941 return -1;
942 }
943 if (i == state->current_line_len) {
944 /* decoder event */
945 return -1;
946 }
25638832 947 char *endptr = NULL;
d3ca65de
AS
948 state->bdat_chunk_len = strtoul((const char *)state->current_line + i,
949 (char **)&endptr, 10);
25638832 950 if ((uint8_t *)endptr == state->current_line + i) {
d3ca65de
AS
951 /* decoder event */
952 return -1;
953 }
954
955 return 0;
956}
957
7c3b22da
VJ
958/* consider 'rset' and 'quit' to be part of the existing state */
959static int NoNewTx(SMTPState *state)
960{
961 if (!(state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
962 if (state->current_line_len >= 4 &&
963 SCMemcmpLowercase("rset", state->current_line, 4) == 0) {
964 return 1;
965 } else if (state->current_line_len >= 4 &&
966 SCMemcmpLowercase("quit", state->current_line, 4) == 0) {
967 return 1;
968 }
969 }
970 return 0;
971}
972
576ec7da 973static int SMTPProcessRequest(SMTPState *state, Flow *f,
9634e60e 974 AppLayerParserState *pstate)
576ec7da 975{
7b0f261f 976 SCEnter();
d209699a
VJ
977 SMTPTransaction *tx = state->curr_tx;
978
7c3b22da 979 if (state->curr_tx == NULL || (state->curr_tx->done && !NoNewTx(state))) {
d209699a
VJ
980 tx = SMTPTransactionCreate();
981 if (tx == NULL)
982 return -1;
983 state->curr_tx = tx;
984 TAILQ_INSERT_TAIL(&state->tx_list, tx, next);
985 tx->tx_id = state->tx_cnt++;
986 }
7b0f261f 987
0d7159b5 988 if (!(state->parser_state & SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
d209699a 989 SMTPSetEvent(state, SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE);
0d7159b5
AS
990 }
991
576ec7da
AS
992 /* there are 2 commands that can push it into this COMMAND_DATA mode -
993 * STARTTLS and DATA */
994 if (!(state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
d3ca65de
AS
995 int r = 0;
996
576ec7da
AS
997 if (state->current_line_len >= 8 &&
998 SCMemcmpLowercase("starttls", state->current_line, 8) == 0) {
999 state->current_command = SMTP_COMMAND_STARTTLS;
1000 } else if (state->current_line_len >= 4 &&
1001 SCMemcmpLowercase("data", state->current_line, 4) == 0) {
1002 state->current_command = SMTP_COMMAND_DATA;
c2dc6867 1003 if (smtp_config.decode_mime) {
d2657bec 1004 tx->mime_state = MimeDecInitParser(f, SMTPProcessDataChunk);
56b74c8b 1005 if (tx->mime_state == NULL) {
c2dc6867
DA
1006 SCLogError(SC_ERR_MEM_ALLOC, "MimeDecInitParser() failed to "
1007 "allocate data");
1008 return MIME_DEC_ERR_MEM;
1009 }
1010
1011 /* Add new MIME message to end of list */
56b74c8b
VJ
1012 if (tx->msg_head == NULL) {
1013 tx->msg_head = tx->mime_state->msg;
1014 tx->msg_tail = tx->mime_state->msg;
c2dc6867
DA
1015 }
1016 else {
56b74c8b
VJ
1017 tx->msg_tail->next = tx->mime_state->msg;
1018 tx->msg_tail = tx->mime_state->msg;
c2dc6867
DA
1019 }
1020 }
1021
d3ca65de
AS
1022 } else if (state->current_line_len >= 4 &&
1023 SCMemcmpLowercase("bdat", state->current_line, 4) == 0) {
1024 r = SMTPParseCommandBDAT(state);
7b0f261f
VJ
1025 if (r == -1) {
1026 SCReturnInt(-1);
1027 }
d3ca65de
AS
1028 state->current_command = SMTP_COMMAND_BDAT;
1029 state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE;
576ec7da
AS
1030 } else {
1031 state->current_command = SMTP_COMMAND_OTHER_CMD;
1032 }
1033
1034 /* Every command is inserted into a command buffer, to be matched
1035 * against reply(ies) sent by the server */
1036 if (SMTPInsertCommandIntoCommandBuffer(state->current_command,
5311cd48 1037 state, f) == -1) {
7b0f261f 1038 SCReturnInt(-1);
576ec7da 1039 }
d3ca65de 1040
7b0f261f 1041 SCReturnInt(r);
576ec7da
AS
1042 }
1043
1044 switch (state->current_command) {
1045 case SMTP_COMMAND_STARTTLS:
1046 return SMTPProcessCommandSTARTTLS(state, f, pstate);
1047
1048 case SMTP_COMMAND_DATA:
1049 return SMTPProcessCommandDATA(state, f, pstate);
1050
d3ca65de
AS
1051 case SMTP_COMMAND_BDAT:
1052 return SMTPProcessCommandBDAT(state, f, pstate);
1053
576ec7da
AS
1054 default:
1055 /* we have nothing to do with any other command at this instant.
1056 * Just let it go through */
7b0f261f 1057 SCReturnInt(0);
576ec7da
AS
1058 }
1059}
1060
88115902 1061static int SMTPParse(int direction, Flow *f, SMTPState *state,
9634e60e 1062 AppLayerParserState *pstate, uint8_t *input,
997eaf42 1063 uint32_t input_len,
429c6388 1064 PatternMatcherQueue *local_data)
576ec7da 1065{
7b0f261f
VJ
1066 SCEnter();
1067
576ec7da
AS
1068 state->input = input;
1069 state->input_len = input_len;
88115902 1070 state->direction = direction;
997eaf42 1071 state->thread_local_data = local_data;
576ec7da 1072
87599bc7
AS
1073 /* toserver */
1074 if (direction == 0) {
1075 while (SMTPGetLine(state) >= 0) {
d3ca65de 1076 if (SMTPProcessRequest(state, f, pstate) == -1)
7b0f261f 1077 SCReturnInt(-1);
87599bc7 1078 }
88115902 1079
87599bc7
AS
1080 /* toclient */
1081 } else {
1082 while (SMTPGetLine(state) >= 0) {
d3ca65de 1083 if (SMTPProcessReply(state, f, pstate) == -1)
7b0f261f 1084 SCReturnInt(-1);
88115902 1085 }
576ec7da
AS
1086 }
1087
7b0f261f 1088 SCReturnInt(0);
576ec7da
AS
1089}
1090
88115902 1091static int SMTPParseClientRecord(Flow *f, void *alstate,
9634e60e 1092 AppLayerParserState *pstate,
576ec7da 1093 uint8_t *input, uint32_t input_len,
429c6388 1094 void *local_data)
576ec7da 1095{
7b0f261f
VJ
1096 SCEnter();
1097
88115902 1098 /* first arg 0 is toserver */
429c6388 1099 return SMTPParse(0, f, alstate, pstate, input, input_len, local_data);
88115902 1100}
576ec7da 1101
88115902 1102static int SMTPParseServerRecord(Flow *f, void *alstate,
9634e60e 1103 AppLayerParserState *pstate,
88115902 1104 uint8_t *input, uint32_t input_len,
429c6388 1105 void *local_data)
88115902 1106{
7b0f261f
VJ
1107 SCEnter();
1108
88115902 1109 /* first arg 1 is toclient */
429c6388 1110 return SMTPParse(1, f, alstate, pstate, input, input_len, local_data);
576ec7da
AS
1111
1112 return 0;
1113}
1114
1115/**
1116 * \internal
1117 * \brief Function to allocate SMTP state memory.
1118 */
d2657bec 1119void *SMTPStateAlloc(void)
576ec7da
AS
1120{
1121 SMTPState *smtp_state = SCMalloc(sizeof(SMTPState));
e176be6f 1122 if (unlikely(smtp_state == NULL))
576ec7da
AS
1123 return NULL;
1124 memset(smtp_state, 0, sizeof(SMTPState));
1125
1126 smtp_state->cmds = SCMalloc(sizeof(uint8_t) *
1127 SMTP_COMMAND_BUFFER_STEPS);
1128 if (smtp_state->cmds == NULL) {
1129 SCFree(smtp_state);
1130 return NULL;
1131 }
1132 smtp_state->cmds_buffer_len = SMTP_COMMAND_BUFFER_STEPS;
1133
56b74c8b
VJ
1134 TAILQ_INIT(&smtp_state->tx_list);
1135
997eaf42
AS
1136 return smtp_state;
1137}
1138
1139static void *SMTPLocalStorageAlloc(void)
1140{
1141 /* needed by the mpm */
1142 PatternMatcherQueue *pmq = SCMalloc(sizeof(PatternMatcherQueue));
e176be6f 1143 if (unlikely(pmq == NULL)) {
4d38a571
AS
1144 exit(EXIT_FAILURE);
1145 }
429c6388 1146 PmqSetup(pmq,
4d38a571
AS
1147 sizeof(smtp_reply_map)/sizeof(SCEnumCharMap) - 2);
1148
997eaf42
AS
1149 return pmq;
1150}
1151
1152static void SMTPLocalStorageFree(void *pmq)
1153{
1154 if (pmq != NULL) {
1155 PmqFree(pmq);
1156 SCFree(pmq);
1157 }
1158
1159 return;
576ec7da
AS
1160}
1161
56b74c8b
VJ
1162static void SMTPTransactionFree(SMTPTransaction *tx, SMTPState *state)
1163{
1164 if (tx->mime_state != NULL) {
1165 MimeDecDeInitParser(tx->mime_state);
1166 }
d209699a
VJ
1167 /* Free list of MIME message recursively */
1168 MimeDecFreeEntity(tx->msg_head);
1169
7b818494 1170 if (tx->decoder_events != NULL)
d209699a 1171 AppLayerDecoderEventsFreeEvents(&tx->decoder_events);
7b818494 1172
e984a572
VJ
1173 if (tx->de_state != NULL)
1174 DetectEngineStateFree(tx->de_state);
d209699a
VJ
1175#if 0
1176 if (tx->decoder_events->cnt <= smtp_state->events)
1177 smtp_state->events -= tx->decoder_events->cnt;
1178 else
1179 smtp_state->events = 0;
1180#endif
56b74c8b
VJ
1181 SCFree(tx);
1182}
1183
576ec7da
AS
1184/**
1185 * \internal
1186 * \brief Function to free SMTP state memory.
1187 */
1188static void SMTPStateFree(void *p)
1189{
1190 SMTPState *smtp_state = (SMTPState *)p;
1191
1192 if (smtp_state->cmds != NULL) {
1193 SCFree(smtp_state->cmds);
1194 }
88115902
AS
1195 if (smtp_state->ts_current_line_db) {
1196 SCFree(smtp_state->ts_db);
1197 }
1198 if (smtp_state->tc_current_line_db) {
1199 SCFree(smtp_state->tc_db);
1200 }
576ec7da 1201
c2dc6867 1202 FileContainerFree(smtp_state->files_ts);
56b74c8b
VJ
1203
1204 SMTPTransaction *tx = NULL;
1205 while ((tx = TAILQ_FIRST(&smtp_state->tx_list))) {
56b74c8b
VJ
1206 TAILQ_REMOVE(&smtp_state->tx_list, tx, next);
1207 SMTPTransactionFree(tx, smtp_state);
1208 }
c2dc6867 1209
576ec7da
AS
1210 SCFree(smtp_state);
1211
1212 return;
1213}
1214
4d38a571
AS
1215static void SMTPSetMpmState(void)
1216{
1217 smtp_mpm_ctx = SCMalloc(sizeof(MpmCtx));
e176be6f 1218 if (unlikely(smtp_mpm_ctx == NULL)) {
4d38a571
AS
1219 exit(EXIT_FAILURE);
1220 }
1221 memset(smtp_mpm_ctx, 0, sizeof(MpmCtx));
a49cbf8a 1222 MpmInitCtx(smtp_mpm_ctx, SMTP_MPM);
4d38a571
AS
1223
1224 smtp_mpm_thread_ctx = SCMalloc(sizeof(MpmThreadCtx));
e176be6f 1225 if (unlikely(smtp_mpm_thread_ctx == NULL)) {
4d38a571
AS
1226 exit(EXIT_FAILURE);
1227 }
1228 memset(smtp_mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
a49cbf8a 1229 MpmInitThreadCtx(smtp_mpm_thread_ctx, SMTP_MPM, 0);
4d38a571
AS
1230
1231 uint32_t i = 0;
1232 for (i = 0; i < sizeof(smtp_reply_map)/sizeof(SCEnumCharMap) - 1; i++) {
1233 SCEnumCharMap *map = &smtp_reply_map[i];
a49cbf8a
AS
1234 /* The third argument is 3, because reply code is always 3 bytes. */
1235 MpmAddPatternCI(smtp_mpm_ctx, (uint8_t *)map->enum_name, 3,
1236 0 /* defunct */, 0 /* defunct */,
1237 i /* pattern id */, 0, 0 /* no flags */);
4d38a571
AS
1238 }
1239
1240 mpm_table[SMTP_MPM].Prepare(smtp_mpm_ctx);
1241}
1242
5e2d9dbd
AS
1243int SMTPStateGetEventInfo(const char *event_name,
1244 int *event_id, AppLayerEventType *event_type)
1245{
1246 *event_id = SCMapEnumNameToValue(event_name, smtp_decoder_event_table);
1247 if (*event_id == -1) {
1248 SCLogError(SC_ERR_INVALID_ENUM_MAP, "event \"%s\" not present in "
1249 "smtp's enum map table.", event_name);
1250 /* yes this is fatal */
1251 return -1;
1252 }
1253
d209699a 1254 *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
5e2d9dbd
AS
1255
1256 return 0;
1257}
1258
429c6388
AS
1259static int SMTPRegisterPatternsForProtocolDetection(void)
1260{
1261 if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMTP,
1262 "EHLO", 4, 0, STREAM_TOSERVER) < 0)
1263 {
1264 return -1;
1265 }
1266 if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMTP,
1267 "HELO", 4, 0, STREAM_TOSERVER) < 0)
1268 {
1269 return -1;
1270 }
1271 if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMTP,
1272 "QUIT", 4, 0, STREAM_TOSERVER) < 0)
1273 {
1274 return -1;
1275 }
1276
1277 return 0;
1278}
1279
56b74c8b
VJ
1280static void SMTPStateTransactionFree (void *state, uint64_t tx_id)
1281{
56b74c8b
VJ
1282 SMTPState *smtp_state = state;
1283 SMTPTransaction *tx = NULL;
1284 TAILQ_FOREACH(tx, &smtp_state->tx_list, next) {
1285 if (tx_id < tx->tx_id)
1286 break;
1287 else if (tx_id > tx->tx_id)
1288 continue;
1289
1290 if (tx == smtp_state->curr_tx)
1291 smtp_state->curr_tx = NULL;
56b74c8b
VJ
1292 TAILQ_REMOVE(&smtp_state->tx_list, tx, next);
1293 SMTPTransactionFree(tx, state);
1294 break;
1295 }
1296
1297
1298}
1299
f32d79df 1300/** \retval cnt highest tx id */
56b74c8b
VJ
1301static uint64_t SMTPStateGetTxCnt(void *state)
1302{
1303 uint64_t cnt = 0;
1304 SMTPState *smtp_state = state;
1305 if (smtp_state) {
f32d79df 1306 cnt = smtp_state->tx_cnt;
56b74c8b
VJ
1307 }
1308 SCLogDebug("returning %"PRIu64, cnt);
1309 return cnt;
1310}
1311
1312static void *SMTPStateGetTx(void *state, uint64_t id)
1313{
1314 SMTPState *smtp_state = state;
1315 if (smtp_state) {
1316 SMTPTransaction *tx = NULL;
1317
1318 if (smtp_state->curr_tx == NULL)
1319 return NULL;
1320 if (smtp_state->curr_tx->tx_id == id)
1321 return smtp_state->curr_tx;
1322
1323 TAILQ_FOREACH(tx, &smtp_state->tx_list, next) {
1324 if (tx->tx_id == id)
1325 return tx;
1326 }
1327 }
56b74c8b
VJ
1328 return NULL;
1329
1330}
1331
1332static int SMTPStateGetAlstateProgressCompletionStatus(uint8_t direction) {
d209699a 1333 return 1;
56b74c8b
VJ
1334}
1335
1336static int SMTPStateGetAlstateProgress(void *vtx, uint8_t direction)
1337{
1338 SMTPTransaction *tx = vtx;
d209699a 1339 return tx->done;
56b74c8b
VJ
1340}
1341
1342static FileContainer *SMTPStateGetFiles(void *state, uint8_t direction)
1343{
1344 if (state == NULL)
1345 return NULL;
1346
1347 SMTPState *smtp_state = (SMTPState *)state;
1348
1349 if (direction & STREAM_TOCLIENT) {
1350 SCReturnPtr(NULL, "FileContainer");
1351 } else {
1352 SCLogDebug("smtp_state->files_ts %p", smtp_state->files_ts);
1353 SCReturnPtr(smtp_state->files_ts, "FileContainer");
1354 }
1355}
1356
08b06bac
VJ
1357static void SMTPStateTruncate(void *state, uint8_t direction)
1358{
1359 FileContainer *fc = SMTPStateGetFiles(state, direction);
1360 if (fc != NULL) {
1361 SCLogDebug("truncating stream, closing files in %s direction (container %p)",
1362 direction & STREAM_TOCLIENT ? "STREAM_TOCLIENT" : "STREAM_TOSERVER", fc);
1363 FileTruncateAllOpenFiles(fc);
1364 }
1365}
1366
d209699a
VJ
1367static AppLayerDecoderEvents *SMTPGetEvents(void *state, uint64_t tx_id)
1368{
1369 SCLogDebug("get SMTP events for TX %"PRIu64, tx_id);
1370
1371 SMTPTransaction *tx = SMTPStateGetTx(state, tx_id);
1372 if (tx != NULL) {
1373 return tx->decoder_events;
1374 }
1375 return NULL;
1376}
1377
e984a572
VJ
1378static DetectEngineState *SMTPGetTxDetectState(void *vtx)
1379{
1380 SMTPTransaction *tx = (SMTPTransaction *)vtx;
1381 return tx->de_state;
1382}
1383
f536099a 1384static int SMTPSetTxDetectState(void *state, void *vtx, DetectEngineState *s)
e984a572
VJ
1385{
1386 SMTPTransaction *tx = (SMTPTransaction *)vtx;
1387 tx->de_state = s;
1388 return 0;
1389}
1390
576ec7da 1391/**
e5c36952 1392 * \brief Register the SMTP Protocol parser.
576ec7da
AS
1393 */
1394void RegisterSMTPParsers(void)
1395{
10966245
AS
1396 char *proto_name = "smtp";
1397
429c6388
AS
1398 if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
1399 AppLayerProtoDetectRegisterProtocol(ALPROTO_SMTP, proto_name);
1400 if (SMTPRegisterPatternsForProtocolDetection() < 0 )
1401 return;
ddde572f
AS
1402 } else {
1403 SCLogInfo("Protocol detection and parser disabled for %s protocol.",
1404 proto_name);
1405 return;
1406 }
576ec7da 1407
429c6388
AS
1408 if (AppLayerParserConfParserEnabled("tcp", proto_name)) {
1409 AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateAlloc, SMTPStateFree);
576ec7da 1410
429c6388
AS
1411 AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_SMTP, STREAM_TOSERVER,
1412 SMTPParseClientRecord);
1413 AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_SMTP, STREAM_TOCLIENT,
1414 SMTPParseServerRecord);
6cb00142 1415
429c6388 1416 AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetEventInfo);
d209699a 1417 AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetEvents);
f536099a 1418 AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_SMTP, NULL,
e984a572 1419 SMTPGetTxDetectState, SMTPSetTxDetectState);
576ec7da 1420
429c6388
AS
1421 AppLayerParserRegisterLocalStorageFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPLocalStorageAlloc,
1422 SMTPLocalStorageFree);
56b74c8b
VJ
1423
1424 AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateTransactionFree);
1425 AppLayerParserRegisterGetFilesFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetFiles);
1426 AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetAlstateProgress);
1427 AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTxCnt);
1428 AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTx);
1429 AppLayerParserRegisterGetStateProgressCompletionStatus(IPPROTO_TCP, ALPROTO_SMTP,
1430 SMTPStateGetAlstateProgressCompletionStatus);
08b06bac 1431 AppLayerParserRegisterTruncateFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateTruncate);
ddde572f
AS
1432 } else {
1433 SCLogInfo("Parsed disabled for %s protocol. Protocol detection"
1434 "still on.", proto_name);
1435 }
997eaf42 1436
4d38a571
AS
1437 SMTPSetMpmState();
1438
c2dc6867
DA
1439 SMTPConfigure();
1440
9faa4b74 1441#ifdef UNITTESTS
429c6388 1442 AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_SMTP, SMTPParserRegisterTests);
9faa4b74 1443#endif
576ec7da
AS
1444 return;
1445}
1446
1447/***************************************Unittests******************************/
1448
87599bc7
AS
1449#ifdef UNITTESTS
1450
576ec7da
AS
1451/*
1452 * \test Test STARTTLS.
1453 */
1454int SMTPParserTest01(void)
1455{
1456 int result = 0;
1457 Flow f;
1458 int r = 0;
1459
1460 /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
1461 uint8_t welcome_reply[] = {
1462 0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
1463 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
1464 0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
1465 0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
1466 0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
1467 0x0d, 0x0a
1468 };
1469 uint32_t welcome_reply_len = sizeof(welcome_reply);
1470
1471 /* EHLO [192.168.0.158]<CR><LF> */
1472 uint8_t request1[] = {
1473 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x5b, 0x31, 0x39,
1474 0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e,
1475 0x31, 0x35, 0x38, 0x5d, 0x0d, 0x0a
1476 };
1477 uint32_t request1_len = sizeof(request1);
1478 /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
1479 * 250-SIZE 35882577<CR><LF>
1480 * 250-8BITMIME<CR><LF>
1481 * 250-STARTTLS<CR><LF>
1482 * 250 ENHANCEDSTATUSCODES<CR><LF>
1483 */
1484 uint8_t reply1[] = {
1485 0x32, 0x35, 0x30, 0x2d, 0x6d, 0x78, 0x2e, 0x67,
1486 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
1487 0x6d, 0x20, 0x61, 0x74, 0x20, 0x79, 0x6f, 0x75,
1488 0x72, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
1489 0x65, 0x2c, 0x20, 0x5b, 0x31, 0x31, 0x37, 0x2e,
1490 0x31, 0x39, 0x38, 0x2e, 0x31, 0x31, 0x35, 0x2e,
1491 0x35, 0x30, 0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30,
1492 0x2d, 0x53, 0x49, 0x5a, 0x45, 0x20, 0x33, 0x35,
1493 0x38, 0x38, 0x32, 0x35, 0x37, 0x37, 0x0d, 0x0a,
1494 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49, 0x54,
1495 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35,
1496 0x30, 0x2d, 0x53, 0x54, 0x41, 0x52, 0x54, 0x54,
1497 0x4c, 0x53, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20,
1498 0x45, 0x4e, 0x48, 0x41, 0x4e, 0x43, 0x45, 0x44,
1499 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x43, 0x4f,
1500 0x44, 0x45, 0x53, 0x0d, 0x0a
1501 };
1502 uint32_t reply1_len = sizeof(reply1);
1503
1504 /* STARTTLS<CR><LF> */
1505 uint8_t request2[] = {
1506 0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
1507 0x0d, 0x0a
1508 };
1509 uint32_t request2_len = sizeof(request2);
1510 /* 220 2.0.0 Ready to start TLS<CR><LF> */
1511 uint8_t reply2[] = {
1512 0x32, 0x32, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
1513 0x30, 0x20, 0x52, 0x65, 0x61, 0x64, 0x79, 0x20,
1514 0x74, 0x6f, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74,
1515 0x20, 0x54, 0x4c, 0x53, 0x0d, 0x0a
1516 };
1517 uint32_t reply2_len = sizeof(reply2);
1518
1519 TcpSession ssn;
8dbf7a0d 1520 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
576ec7da
AS
1521
1522 memset(&f, 0, sizeof(f));
1523 memset(&ssn, 0, sizeof(ssn));
1524
1525 FLOW_INITIALIZE(&f);
1526 f.protoctx = (void *)&ssn;
429c6388 1527 f.proto = IPPROTO_TCP;
576ec7da
AS
1528
1529 StreamTcpInitConfig(TRUE);
576ec7da 1530
cd3e32ce 1531 SCMutexLock(&f.m);
429c6388
AS
1532 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
1533 welcome_reply, welcome_reply_len);
576ec7da
AS
1534 if (r != 0) {
1535 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1536 SCMutexUnlock(&f.m);
576ec7da
AS
1537 goto end;
1538 }
cd3e32ce 1539 SCMutexUnlock(&f.m);
06904c90 1540 SMTPState *smtp_state = f.alstate;
576ec7da
AS
1541 if (smtp_state == NULL) {
1542 printf("no smtp state: ");
1543 goto end;
1544 }
1545 if (smtp_state->input_len != 0 ||
0d7159b5 1546 smtp_state->cmds_cnt != 0 ||
576ec7da 1547 smtp_state->cmds_idx != 0 ||
0d7159b5 1548 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
576ec7da
AS
1549 printf("smtp parser in inconsistent state\n");
1550 goto end;
1551 }
1552
cd3e32ce 1553 SCMutexLock(&f.m);
429c6388
AS
1554 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
1555 request1, request1_len);
576ec7da
AS
1556 if (r != 0) {
1557 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1558 SCMutexUnlock(&f.m);
576ec7da
AS
1559 goto end;
1560 }
cd3e32ce 1561 SCMutexUnlock(&f.m);
576ec7da 1562 if (smtp_state->input_len != 0 ||
576ec7da
AS
1563 smtp_state->cmds_cnt != 1 ||
1564 smtp_state->cmds_idx != 0 ||
1565 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1566 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1567 printf("smtp parser in inconsistent state\n");
1568 goto end;
1569 }
1570
cd3e32ce 1571 SCMutexLock(&f.m);
429c6388
AS
1572 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
1573 reply1, reply1_len);
576ec7da
AS
1574 if (r != 0) {
1575 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1576 SCMutexUnlock(&f.m);
576ec7da
AS
1577 goto end;
1578 }
cd3e32ce 1579 SCMutexUnlock(&f.m);
576ec7da 1580 if (smtp_state->input_len != 0 ||
576ec7da
AS
1581 smtp_state->cmds_cnt != 0 ||
1582 smtp_state->cmds_idx != 0 ||
1583 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1584 printf("smtp parser in inconsistent state\n");
1585 goto end;
1586 }
1587
cd3e32ce 1588 SCMutexLock(&f.m);
429c6388
AS
1589 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
1590 request2, request2_len);
576ec7da
AS
1591 if (r != 0) {
1592 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1593 SCMutexUnlock(&f.m);
576ec7da
AS
1594 goto end;
1595 }
cd3e32ce 1596 SCMutexUnlock(&f.m);
576ec7da 1597 if (smtp_state->input_len != 0 ||
576ec7da
AS
1598 smtp_state->cmds_cnt != 1 ||
1599 smtp_state->cmds_idx != 0 ||
1600 smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS ||
1601 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1602 printf("smtp parser in inconsistent state\n");
1603 goto end;
1604 }
1605
cd3e32ce 1606 SCMutexLock(&f.m);
429c6388
AS
1607 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
1608 reply2, reply2_len);
576ec7da
AS
1609 if (r != 0) {
1610 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1611 SCMutexUnlock(&f.m);
576ec7da
AS
1612 goto end;
1613 }
cd3e32ce 1614 SCMutexUnlock(&f.m);
576ec7da 1615 if (smtp_state->input_len != 0 ||
576ec7da
AS
1616 smtp_state->cmds_cnt != 0 ||
1617 smtp_state->cmds_idx != 0 ||
1618 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
1619 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1620 printf("smtp parser in inconsistent state\n");
1621 goto end;
1622 }
1623
1624 if (!(f.flags & FLOW_NOPAYLOAD_INSPECTION) ||
c1558f5a 1625 !(ssn.flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) ||
576ec7da
AS
1626 !(((TcpSession *)f.protoctx)->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) ||
1627 !(((TcpSession *)f.protoctx)->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
1628 goto end;
1629 }
1630
1631 result = 1;
1632end:
429c6388 1633 if (alp_tctx != NULL)
fdefb65b 1634 AppLayerParserThreadCtxFree(alp_tctx);
576ec7da
AS
1635 StreamTcpFreeConfig(TRUE);
1636 FLOW_DESTROY(&f);
1637 return result;
1638}
1639
1640/**
1641 * \test Test multiple DATA commands(full mail transactions).
1642 */
1643int SMTPParserTest02(void)
1644{
1645 int result = 0;
1646 Flow f;
1647 int r = 0;
1648
1649 /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
1650 uint8_t welcome_reply[] = {
1651 0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
1652 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
1653 0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
1654 0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
1655 0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
1656 0x0d, 0x0a
1657 };
1658 uint32_t welcome_reply_len = sizeof(welcome_reply);
1659
1660 /* EHLO boo.com<CR><LF> */
1661 uint8_t request1[] = {
1662 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
1663 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
1664 };
1665 uint32_t request1_len = sizeof(request1);
1666 /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
1667 * 250-SIZE 35882577<CR><LF>
1668 * 250-8BITMIME<CR><LF>
1669 * 250-STARTTLS<CR><LF>
1670 * 250 ENHANCEDSTATUSCODES<CR><LF>
1671 */
1672 uint8_t reply1[] = {
1673 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
1674 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
1675 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
1676 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
1677 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
1678 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
1679 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
1680 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
1681 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
1682 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
1683 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
1684 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
1685 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
1686 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
1687 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
1688 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
1689 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
1690 };
1691 uint32_t reply1_len = sizeof(reply1);
1692
1693 /* MAIL FROM:asdff@asdf.com<CR><LF> */
1694 uint8_t request2[] = {
1695 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
1696 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
1697 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
1698 0x0d, 0x0a
1699 };
1700 uint32_t request2_len = sizeof(request2);
1701 /* 250 2.1.0 Ok<CR><LF> */
1702 uint8_t reply2[] = {
1703 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
1704 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
1705 };
1706 uint32_t reply2_len = sizeof(reply2);
1707
1708 /* RCPT TO:bimbs@gmail.com<CR><LF> */
1709 uint8_t request3[] = {
1710 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
1711 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
1712 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
1713 0x0a
1714 };
1715 uint32_t request3_len = sizeof(request3);
1716 /* 250 2.1.5 Ok<CR><LF> */
1717 uint8_t reply3[] = {
1718 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
1719 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
1720 };
1721 uint32_t reply3_len = sizeof(reply3);
1722
1723 /* DATA<CR><LF> */
1724 uint8_t request4[] = {
1725 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
1726 };
1727 uint32_t request4_len = sizeof(request4);
1728 /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
1729 uint8_t reply4[] = {
1730 0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
1731 0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
1732 0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
1733 0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
1734 0x4c, 0x46, 0x3e, 0x0d, 0x0a
1735 };
1736 uint32_t reply4_len = sizeof(reply4);
1737
1738 /* FROM:asdff@asdf.com<CR><LF> */
1739 uint8_t request5_1[] = {
1740 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
1741 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
1742 0x63, 0x6f, 0x6d, 0x0d, 0x0a
1743 };
1744 uint32_t request5_1_len = sizeof(request5_1);
1745 /* TO:bimbs@gmail.com<CR><LF> */
1746 uint8_t request5_2[] = {
1747 0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73,
1748 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63,
1749 0x6f, 0x6d, 0x0d, 0x0a
1750 };
1751 uint32_t request5_2_len = sizeof(request5_2);
1752 /* <CR><LF> */
1753 uint8_t request5_3[] = {
1754 0x0d, 0x0a
1755 };
1756 uint32_t request5_3_len = sizeof(request5_3);
1757 /* this is test mail1<CR><LF> */
1758 uint8_t request5_4[] = {
1759 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
1760 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x69,
1761 0x6c, 0x31, 0x0d, 0x0a
1762 };
1763 uint32_t request5_4_len = sizeof(request5_4);
1764 /* .<CR><LF> */
1765 uint8_t request5_5[] = {
1766 0x2e, 0x0d, 0x0a
1767 };
1768 uint32_t request5_5_len = sizeof(request5_5);
1769 /* 250 2.0.0 Ok: queued as 6A1AF20BF2<CR><LF> */
1770 uint8_t reply5[] = {
1771 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
1772 0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
1773 0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
1774 0x36, 0x41, 0x31, 0x41, 0x46, 0x32, 0x30, 0x42,
1775 0x46, 0x32, 0x0d, 0x0a
1776 };
1777 uint32_t reply5_len = sizeof(reply5);
1778
1779 /* MAIL FROM:asdfg@asdf.com<CR><LF> */
1780 uint8_t request6[] = {
1781 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
1782 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x67, 0x40,
1783 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
1784 0x0d, 0x0a
1785 };
1786 uint32_t request6_len = sizeof(request6);
1787 /* 250 2.1.0 Ok<CR><LF> */
1788 uint8_t reply6[] = {
1789 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
1790 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
1791 };
1792 uint32_t reply6_len = sizeof(reply6);
1793
1794 /* RCPT TO:bimbs@gmail.com<CR><LF> */
1795 uint8_t request7[] = {
1796 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
1797 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
1798 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
1799 0x0a
1800 };
1801 uint32_t request7_len = sizeof(request7);
1802 /* 250 2.1.5 Ok<CR><LF> */
1803 uint8_t reply7[] = {
1804 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
1805 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
1806 };
1807 uint32_t reply7_len = sizeof(reply7);
1808
1809 /* DATA<CR><LF> */
1810 uint8_t request8[] = {
1811 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
1812 };
1813 uint32_t request8_len = sizeof(request8);
1814 /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
1815 uint8_t reply8[] = {
1816 0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
1817 0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
1818 0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
1819 0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
1820 0x4c, 0x46, 0x3e, 0x0d, 0x0a
1821 };
1822 uint32_t reply8_len = sizeof(reply8);
1823
1824 /* FROM:asdfg@gmail.com<CR><LF> */
1825 uint8_t request9_1[] = {
1826 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
1827 0x66, 0x67, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c,
1828 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
1829 };
1830 uint32_t request9_1_len = sizeof(request9_1);
1831 /* TO:bimbs@gmail.com<CR><LF> */
1832 uint8_t request9_2[] = {
1833 0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73,
1834 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63,
1835 0x6f, 0x6d, 0x0d, 0x0a
1836 };
1837 uint32_t request9_2_len = sizeof(request9_2);
1838 /* <CR><LF> */
1839 uint8_t request9_3[] = {
1840 0x0d, 0x0a
1841 };
1842 uint32_t request9_3_len = sizeof(request9_3);
1843 /* this is test mail2<CR><LF> */
1844 uint8_t request9_4[] = {
1845 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
1846 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x69,
1847 0x6c, 0x32, 0x0d, 0x0a
1848 };
1849 uint32_t request9_4_len = sizeof(request9_4);
1850 /* .<CR><LF> */
1851 uint8_t request9_5[] = {
1852 0x2e, 0x0d, 0x0a
1853 };
1854 uint32_t request9_5_len = sizeof(request9_5);
1855 /* 250 2.0.0 Ok: queued as 28CFF20BF2<CR><LF> */
1856 uint8_t reply9[] = {
1857 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
1858 0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
1859 0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
1860 0x32, 0x38, 0x43, 0x46, 0x46, 0x32, 0x30, 0x42,
1861 0x46, 0x32, 0x0d, 0x0a
1862 };
1863 uint32_t reply9_len = sizeof(reply9);
1864
1865 /* QUIT<CR><LF> */
1866 uint8_t request10[] = {
1867 0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
1868 };
1869 uint32_t request10_len = sizeof(request10);
1870 /* 221 2.0.0 Bye<CR><LF> */
1871 uint8_t reply10[] = {
1872 0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
1873 0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
1874 };
1875 uint32_t reply10_len = sizeof(reply10);
1876
1877 TcpSession ssn;
8dbf7a0d 1878 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
576ec7da
AS
1879
1880 memset(&f, 0, sizeof(f));
1881 memset(&ssn, 0, sizeof(ssn));
1882
1883 FLOW_INITIALIZE(&f);
1884 f.protoctx = (void *)&ssn;
429c6388 1885 f.proto = IPPROTO_TCP;
576ec7da
AS
1886
1887 StreamTcpInitConfig(TRUE);
576ec7da 1888
cd3e32ce 1889 SCMutexLock(&f.m);
429c6388
AS
1890 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
1891 welcome_reply, welcome_reply_len);
576ec7da
AS
1892 if (r != 0) {
1893 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1894 SCMutexUnlock(&f.m);
576ec7da
AS
1895 goto end;
1896 }
cd3e32ce 1897 SCMutexUnlock(&f.m);
06904c90 1898 SMTPState *smtp_state = f.alstate;
576ec7da
AS
1899 if (smtp_state == NULL) {
1900 printf("no smtp state: ");
1901 goto end;
1902 }
1903 if (smtp_state->input_len != 0 ||
0d7159b5 1904 smtp_state->cmds_cnt != 0 ||
576ec7da 1905 smtp_state->cmds_idx != 0 ||
0d7159b5 1906 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
576ec7da
AS
1907 printf("smtp parser in inconsistent state\n");
1908 goto end;
1909 }
1910
cd3e32ce 1911 SCMutexLock(&f.m);
429c6388
AS
1912 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
1913 request1, request1_len);
576ec7da
AS
1914 if (r != 0) {
1915 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1916 SCMutexUnlock(&f.m);
576ec7da
AS
1917 goto end;
1918 }
cd3e32ce 1919 SCMutexUnlock(&f.m);
576ec7da 1920 if (smtp_state->input_len != 0 ||
576ec7da
AS
1921 smtp_state->cmds_cnt != 1 ||
1922 smtp_state->cmds_idx != 0 ||
1923 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1924 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1925 printf("smtp parser in inconsistent state\n");
1926 goto end;
1927 }
1928
cd3e32ce 1929 SCMutexLock(&f.m);
429c6388
AS
1930 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
1931 reply1, reply1_len);
576ec7da
AS
1932 if (r != 0) {
1933 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1934 SCMutexUnlock(&f.m);
576ec7da
AS
1935 goto end;
1936 }
cd3e32ce 1937 SCMutexUnlock(&f.m);
576ec7da 1938 if (smtp_state->input_len != 0 ||
576ec7da
AS
1939 smtp_state->cmds_cnt != 0 ||
1940 smtp_state->cmds_idx != 0 ||
1941 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1942 printf("smtp parser in inconsistent state\n");
1943 goto end;
1944 }
1945
cd3e32ce 1946 SCMutexLock(&f.m);
429c6388
AS
1947 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
1948 request2, request2_len);
576ec7da
AS
1949 if (r != 0) {
1950 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1951 SCMutexUnlock(&f.m);
576ec7da
AS
1952 goto end;
1953 }
cd3e32ce 1954 SCMutexUnlock(&f.m);
576ec7da 1955 if (smtp_state->input_len != 0 ||
576ec7da
AS
1956 smtp_state->cmds_cnt != 1 ||
1957 smtp_state->cmds_idx != 0 ||
1958 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1959 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1960 printf("smtp parser in inconsistent state\n");
1961 goto end;
1962 }
1963
cd3e32ce 1964 SCMutexLock(&f.m);
429c6388
AS
1965 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
1966 reply2, reply2_len);
576ec7da
AS
1967 if (r != 0) {
1968 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1969 SCMutexUnlock(&f.m);
576ec7da
AS
1970 goto end;
1971 }
cd3e32ce 1972 SCMutexUnlock(&f.m);
576ec7da 1973 if (smtp_state->input_len != 0 ||
576ec7da
AS
1974 smtp_state->cmds_cnt != 0 ||
1975 smtp_state->cmds_idx != 0 ||
1976 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
1977 printf("smtp parser in inconsistent state\n");
1978 goto end;
1979 }
1980
cd3e32ce 1981 SCMutexLock(&f.m);
429c6388
AS
1982 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
1983 request3, request3_len);
576ec7da
AS
1984 if (r != 0) {
1985 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 1986 SCMutexUnlock(&f.m);
576ec7da
AS
1987 goto end;
1988 }
cd3e32ce 1989 SCMutexUnlock(&f.m);
576ec7da 1990 if (smtp_state->input_len != 0 ||
576ec7da
AS
1991 smtp_state->cmds_cnt != 1 ||
1992 smtp_state->cmds_idx != 0 ||
1993 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1994 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1995 printf("smtp parser in inconsistent state\n");
1996 goto end;
1997 }
1998
cd3e32ce 1999 SCMutexLock(&f.m);
429c6388
AS
2000 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
2001 reply3, reply3_len);
576ec7da
AS
2002 if (r != 0) {
2003 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2004 SCMutexUnlock(&f.m);
576ec7da
AS
2005 goto end;
2006 }
cd3e32ce 2007 SCMutexUnlock(&f.m);
576ec7da 2008 if (smtp_state->input_len != 0 ||
576ec7da
AS
2009 smtp_state->cmds_cnt != 0 ||
2010 smtp_state->cmds_idx != 0 ||
2011 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2012 printf("smtp parser in inconsistent state\n");
2013 goto end;
2014 }
2015
cd3e32ce 2016 SCMutexLock(&f.m);
429c6388
AS
2017 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2018 request4, request4_len);
576ec7da
AS
2019 if (r != 0) {
2020 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2021 SCMutexUnlock(&f.m);
576ec7da
AS
2022 goto end;
2023 }
cd3e32ce 2024 SCMutexUnlock(&f.m);
576ec7da 2025 if (smtp_state->input_len != 0 ||
576ec7da
AS
2026 smtp_state->cmds_cnt != 1 ||
2027 smtp_state->cmds_idx != 0 ||
2028 smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
2029 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2030 printf("smtp parser in inconsistent state\n");
2031 goto end;
2032 }
2033
cd3e32ce 2034 SCMutexLock(&f.m);
429c6388
AS
2035 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
2036 reply4, reply4_len);
576ec7da
AS
2037 if (r != 0) {
2038 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2039 SCMutexUnlock(&f.m);
576ec7da
AS
2040 goto end;
2041 }
cd3e32ce 2042 SCMutexUnlock(&f.m);
576ec7da 2043 if (smtp_state->input_len != 0 ||
576ec7da
AS
2044 smtp_state->cmds_cnt != 0 ||
2045 smtp_state->cmds_idx != 0 ||
2046 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2047 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
2048 printf("smtp parser in inconsistent state\n");
2049 goto end;
2050 }
2051
cd3e32ce 2052 SCMutexLock(&f.m);
429c6388
AS
2053 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2054 request5_1, request5_1_len);
576ec7da
AS
2055 if (r != 0) {
2056 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2057 SCMutexUnlock(&f.m);
576ec7da
AS
2058 goto end;
2059 }
cd3e32ce 2060 SCMutexUnlock(&f.m);
576ec7da 2061 if (smtp_state->input_len != 0 ||
576ec7da
AS
2062 smtp_state->cmds_cnt != 0 ||
2063 smtp_state->cmds_idx != 0 ||
2064 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2065 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
2066
2067 printf("smtp parser in inconsistent state\n");
2068 goto end;
2069 }
2070
cd3e32ce 2071 SCMutexLock(&f.m);
429c6388
AS
2072 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2073 request5_2, request5_2_len);
576ec7da
AS
2074 if (r != 0) {
2075 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2076 SCMutexUnlock(&f.m);
576ec7da
AS
2077 goto end;
2078 }
cd3e32ce 2079 SCMutexUnlock(&f.m);
576ec7da 2080 if (smtp_state->input_len != 0 ||
576ec7da
AS
2081 smtp_state->cmds_cnt != 0 ||
2082 smtp_state->cmds_idx != 0 ||
2083 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2084 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
2085
2086 printf("smtp parser in inconsistent state\n");
2087 goto end;
2088 }
2089
cd3e32ce 2090 SCMutexLock(&f.m);
429c6388
AS
2091 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2092 request5_3, request5_3_len);
576ec7da
AS
2093 if (r != 0) {
2094 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2095 SCMutexUnlock(&f.m);
576ec7da
AS
2096 goto end;
2097 }
cd3e32ce 2098 SCMutexUnlock(&f.m);
576ec7da 2099 if (smtp_state->input_len != 0 ||
576ec7da
AS
2100 smtp_state->cmds_cnt != 0 ||
2101 smtp_state->cmds_idx != 0 ||
2102 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2103 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
2104
2105 printf("smtp parser in inconsistent state\n");
2106 goto end;
2107 }
2108
cd3e32ce 2109 SCMutexLock(&f.m);
429c6388
AS
2110 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2111 request5_4, request5_4_len);
576ec7da
AS
2112 if (r != 0) {
2113 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2114 SCMutexUnlock(&f.m);
576ec7da
AS
2115 goto end;
2116 }
cd3e32ce 2117 SCMutexUnlock(&f.m);
576ec7da 2118 if (smtp_state->input_len != 0 ||
576ec7da
AS
2119 smtp_state->cmds_cnt != 0 ||
2120 smtp_state->cmds_idx != 0 ||
2121 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2122 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
2123
2124 printf("smtp parser in inconsistent state\n");
2125 goto end;
2126 }
2127
cd3e32ce 2128 SCMutexLock(&f.m);
429c6388
AS
2129 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2130 request5_5, request5_5_len);
576ec7da
AS
2131 if (r != 0) {
2132 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2133 SCMutexUnlock(&f.m);
576ec7da
AS
2134 goto end;
2135 }
cd3e32ce 2136 SCMutexUnlock(&f.m);
576ec7da 2137 if (smtp_state->input_len != 0 ||
576ec7da
AS
2138 smtp_state->cmds_cnt != 1 ||
2139 smtp_state->cmds_idx != 0 ||
2140 smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
2141 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2142 printf("smtp parser in inconsistent state\n");
2143 goto end;
2144 }
2145
cd3e32ce 2146 SCMutexLock(&f.m);
429c6388
AS
2147 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
2148 reply5, reply5_len);
576ec7da
AS
2149 if (r != 0) {
2150 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2151 SCMutexUnlock(&f.m);
576ec7da
AS
2152 goto end;
2153 }
cd3e32ce 2154 SCMutexUnlock(&f.m);
576ec7da 2155 if (smtp_state->input_len != 0 ||
576ec7da
AS
2156 smtp_state->cmds_cnt != 0 ||
2157 smtp_state->cmds_idx != 0 ||
2158 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2159 printf("smtp parser in inconsistent state\n");
2160 goto end;
2161 }
2162
cd3e32ce 2163 SCMutexLock(&f.m);
429c6388
AS
2164 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2165 request6, request6_len);
576ec7da
AS
2166 if (r != 0) {
2167 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2168 SCMutexUnlock(&f.m);
576ec7da
AS
2169 goto end;
2170 }
cd3e32ce 2171 SCMutexUnlock(&f.m);
576ec7da 2172 if (smtp_state->input_len != 0 ||
576ec7da
AS
2173 smtp_state->cmds_cnt != 1 ||
2174 smtp_state->cmds_idx != 0 ||
2175 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2176 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2177 printf("smtp parser in inconsistent state\n");
2178 goto end;
2179 }
2180
cd3e32ce 2181 SCMutexLock(&f.m);
429c6388
AS
2182 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
2183 reply6, reply6_len);
576ec7da
AS
2184 if (r != 0) {
2185 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2186 SCMutexUnlock(&f.m);
576ec7da
AS
2187 goto end;
2188 }
cd3e32ce 2189 SCMutexUnlock(&f.m);
576ec7da 2190 if (smtp_state->input_len != 0 ||
576ec7da
AS
2191 smtp_state->cmds_cnt != 0 ||
2192 smtp_state->cmds_idx != 0 ||
2193 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2194 printf("smtp parser in inconsistent state\n");
2195 goto end;
2196 }
2197
cd3e32ce 2198 SCMutexLock(&f.m);
429c6388
AS
2199 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2200 request7, request7_len);
576ec7da
AS
2201 if (r != 0) {
2202 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2203 SCMutexUnlock(&f.m);
576ec7da
AS
2204 goto end;
2205 }
cd3e32ce 2206 SCMutexUnlock(&f.m);
576ec7da 2207 if (smtp_state->input_len != 0 ||
576ec7da
AS
2208 smtp_state->cmds_cnt != 1 ||
2209 smtp_state->cmds_idx != 0 ||
2210 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2211 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2212 printf("smtp parser in inconsistent state\n");
2213 goto end;
2214 }
2215
cd3e32ce 2216 SCMutexLock(&f.m);
429c6388
AS
2217 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
2218 reply7, reply7_len);
576ec7da
AS
2219 if (r != 0) {
2220 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2221 SCMutexUnlock(&f.m);
576ec7da
AS
2222 goto end;
2223 }
cd3e32ce 2224 SCMutexUnlock(&f.m);
576ec7da 2225 if (smtp_state->input_len != 0 ||
576ec7da
AS
2226 smtp_state->cmds_cnt != 0 ||
2227 smtp_state->cmds_idx != 0 ||
2228 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2229 printf("smtp parser in inconsistent state\n");
2230 goto end;
2231 }
2232
cd3e32ce 2233 SCMutexLock(&f.m);
429c6388
AS
2234 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2235 request8, request8_len);
576ec7da
AS
2236 if (r != 0) {
2237 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2238 SCMutexUnlock(&f.m);
576ec7da
AS
2239 goto end;
2240 }
cd3e32ce 2241 SCMutexUnlock(&f.m);
576ec7da 2242 if (smtp_state->input_len != 0 ||
576ec7da
AS
2243 smtp_state->cmds_cnt != 1 ||
2244 smtp_state->cmds_idx != 0 ||
2245 smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
2246 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2247 printf("smtp parser in inconsistent state\n");
2248 goto end;
2249 }
2250
cd3e32ce 2251 SCMutexLock(&f.m);
429c6388
AS
2252 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
2253 reply8, reply8_len);
576ec7da
AS
2254 if (r != 0) {
2255 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2256 SCMutexUnlock(&f.m);
576ec7da
AS
2257 goto end;
2258 }
cd3e32ce 2259 SCMutexUnlock(&f.m);
576ec7da 2260 if (smtp_state->input_len != 0 ||
576ec7da
AS
2261 smtp_state->cmds_cnt != 0 ||
2262 smtp_state->cmds_idx != 0 ||
2263 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2264 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
2265 printf("smtp parser in inconsistent state\n");
2266 goto end;
2267 }
2268
cd3e32ce 2269 SCMutexLock(&f.m);
429c6388
AS
2270 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2271 request9_1, request9_1_len);
576ec7da
AS
2272 if (r != 0) {
2273 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2274 SCMutexUnlock(&f.m);
576ec7da
AS
2275 goto end;
2276 }
cd3e32ce 2277 SCMutexUnlock(&f.m);
576ec7da 2278 if (smtp_state->input_len != 0 ||
576ec7da
AS
2279 smtp_state->cmds_cnt != 0 ||
2280 smtp_state->cmds_idx != 0 ||
2281 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2282 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
2283
2284 printf("smtp parser in inconsistent state\n");
2285 goto end;
2286 }
2287
cd3e32ce 2288 SCMutexLock(&f.m);
429c6388
AS
2289 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2290 request9_2, request9_2_len);
576ec7da
AS
2291 if (r != 0) {
2292 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2293 SCMutexUnlock(&f.m);
576ec7da
AS
2294 goto end;
2295 }
cd3e32ce 2296 SCMutexUnlock(&f.m);
576ec7da 2297 if (smtp_state->input_len != 0 ||
576ec7da
AS
2298 smtp_state->cmds_cnt != 0 ||
2299 smtp_state->cmds_idx != 0 ||
2300 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2301 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
2302
2303 printf("smtp parser in inconsistent state\n");
2304 goto end;
2305 }
2306
cd3e32ce 2307 SCMutexLock(&f.m);
429c6388
AS
2308 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2309 request9_3, request9_3_len);
576ec7da
AS
2310 if (r != 0) {
2311 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2312 SCMutexUnlock(&f.m);
576ec7da
AS
2313 goto end;
2314 }
cd3e32ce 2315 SCMutexUnlock(&f.m);
576ec7da 2316 if (smtp_state->input_len != 0 ||
576ec7da
AS
2317 smtp_state->cmds_cnt != 0 ||
2318 smtp_state->cmds_idx != 0 ||
2319 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2320 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
2321
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 request9_4, request9_4_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 != 0 ||
2337 smtp_state->cmds_idx != 0 ||
2338 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2339 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
2340
2341 printf("smtp parser in inconsistent state\n");
2342 goto end;
2343 }
2344
cd3e32ce 2345 SCMutexLock(&f.m);
429c6388
AS
2346 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2347 request9_5, request9_5_len);
576ec7da
AS
2348 if (r != 0) {
2349 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2350 SCMutexUnlock(&f.m);
576ec7da
AS
2351 goto end;
2352 }
cd3e32ce 2353 SCMutexUnlock(&f.m);
576ec7da 2354 if (smtp_state->input_len != 0 ||
576ec7da
AS
2355 smtp_state->cmds_cnt != 1 ||
2356 smtp_state->cmds_idx != 0 ||
2357 smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
2358 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2359 printf("smtp parser in inconsistent state\n");
2360 goto end;
2361 }
2362
cd3e32ce 2363 SCMutexLock(&f.m);
429c6388
AS
2364 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
2365 reply9, reply9_len);
576ec7da
AS
2366 if (r != 0) {
2367 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2368 SCMutexUnlock(&f.m);
576ec7da
AS
2369 goto end;
2370 }
cd3e32ce 2371 SCMutexUnlock(&f.m);
576ec7da 2372 if (smtp_state->input_len != 0 ||
576ec7da
AS
2373 smtp_state->cmds_cnt != 0 ||
2374 smtp_state->cmds_idx != 0 ||
2375 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2376 printf("smtp parser in inconsistent state\n");
2377 goto end;
2378 }
2379
cd3e32ce 2380 SCMutexLock(&f.m);
429c6388
AS
2381 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2382 request10, request10_len);
576ec7da
AS
2383 if (r != 0) {
2384 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2385 SCMutexUnlock(&f.m);
576ec7da
AS
2386 goto end;
2387 }
cd3e32ce 2388 SCMutexUnlock(&f.m);
576ec7da 2389 if (smtp_state->input_len != 0 ||
576ec7da
AS
2390 smtp_state->cmds_cnt != 1 ||
2391 smtp_state->cmds_idx != 0 ||
2392 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2393 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2394 printf("smtp parser in inconsistent state\n");
2395 goto end;
2396 }
2397
cd3e32ce 2398 SCMutexLock(&f.m);
429c6388
AS
2399 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
2400 reply10, reply10_len);
576ec7da
AS
2401 if (r != 0) {
2402 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2403 SCMutexUnlock(&f.m);
576ec7da
AS
2404 goto end;
2405 }
cd3e32ce 2406 SCMutexUnlock(&f.m);
576ec7da 2407 if (smtp_state->input_len != 0 ||
576ec7da
AS
2408 smtp_state->cmds_cnt != 0 ||
2409 smtp_state->cmds_idx != 0 ||
2410 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2411 printf("smtp parser in inconsistent state\n");
2412 goto end;
2413 }
2414
2415 result = 1;
2416end:
429c6388 2417 if (alp_tctx != NULL)
fdefb65b 2418 AppLayerParserThreadCtxFree(alp_tctx);
576ec7da
AS
2419 StreamTcpFreeConfig(TRUE);
2420 FLOW_DESTROY(&f);
2421 return result;
2422}
2423
2424/**
2425 * \test Testing parsing pipelined commands.
2426 */
2427int SMTPParserTest03(void)
2428{
2429 int result = 0;
2430 Flow f;
2431 int r = 0;
2432
2433 /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
2434 uint8_t welcome_reply[] = {
2435 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
2436 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2437 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2438 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
2439 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
2440 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
2441 };
2442 uint32_t welcome_reply_len = sizeof(welcome_reply);
2443
2444 /* EHLO boo.com<CR><LF> */
2445 uint8_t request1[] = {
2446 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
2447 0x2e, 0x63, 0x6f, 0x6d, 0x0a
2448 };
2449 uint32_t request1_len = sizeof(request1);
2450 /* 250-poona_slack_vm1.localdomain<CR><LF>
2451 * 250-PIPELINING<CR><LF>
2452 * 250-SIZE 10240000<CR><LF>
2453 * 250-VRFY<CR><LF>
2454 * 250-ETRN<CR><LF>
2455 * 250-ENHANCEDSTATUSCODES<CR><LF>
2456 * 250-8BITMIME<CR><LF>
2457 * 250 DSN<CR><LF>
2458 */
2459 uint8_t reply1[] = {
2460 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
2461 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2462 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2463 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
2464 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
2465 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
2466 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
2467 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
2468 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
2469 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
2470 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
2471 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
2472 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
2473 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
2474 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
2475 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
2476 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
2477 };
2478 uint32_t reply1_len = sizeof(reply1);
2479
2480 /* MAIL FROM:pbsf@asdfs.com<CR><LF>
2481 * RCPT TO:pbsf@asdfs.com<CR><LF>
2482 * DATA<CR><LF>
2483 */
2484 uint8_t request2[] = {
2485 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
2486 0x4d, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
2487 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
2488 0x0d, 0x0a, 0x52, 0x43, 0x50, 0x54, 0x20, 0x54,
2489 0x4f, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
2490 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
2491 0x0d, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
2492 };
2493 uint32_t request2_len = sizeof(request2);
2494 /* 250 2.1.0 Ok<CR><LF>
2495 * 250 2.1.5 Ok<CR><LF>
2496 * 354 End data with <CR><LF>.<CR><LF>|<CR><LF>|
2497 */
2498 uint8_t reply2[] = {
2499 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2500 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a, 0x32, 0x35,
2501 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, 0x35, 0x20,
2502 0x4f, 0x6b, 0x0d, 0x0a, 0x33, 0x35, 0x34, 0x20,
2503 0x45, 0x6e, 0x64, 0x20, 0x64, 0x61, 0x74, 0x61,
2504 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x3c, 0x43,
2505 0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x2e, 0x3c,
2506 0x43, 0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x0d,
2507 0x0a
2508 };
2509 uint32_t reply2_len = sizeof(reply2);
2510
2511 TcpSession ssn;
8dbf7a0d 2512 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
576ec7da
AS
2513
2514 memset(&f, 0, sizeof(f));
2515 memset(&ssn, 0, sizeof(ssn));
2516
2517 FLOW_INITIALIZE(&f);
2518 f.protoctx = (void *)&ssn;
429c6388 2519 f.proto = IPPROTO_TCP;
576ec7da
AS
2520
2521 StreamTcpInitConfig(TRUE);
576ec7da 2522
cd3e32ce 2523 SCMutexLock(&f.m);
429c6388
AS
2524 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
2525 welcome_reply, welcome_reply_len);
576ec7da
AS
2526 if (r != 0) {
2527 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2528 SCMutexUnlock(&f.m);
576ec7da
AS
2529 goto end;
2530 }
cd3e32ce 2531 SCMutexUnlock(&f.m);
06904c90 2532 SMTPState *smtp_state = f.alstate;
576ec7da
AS
2533 if (smtp_state == NULL) {
2534 printf("no smtp state: ");
2535 goto end;
2536 }
2537 if (smtp_state->input_len != 0 ||
0d7159b5 2538 smtp_state->cmds_cnt != 0 ||
576ec7da 2539 smtp_state->cmds_idx != 0 ||
0d7159b5 2540 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
576ec7da
AS
2541 printf("smtp parser in inconsistent state\n");
2542 goto end;
2543 }
2544
cd3e32ce 2545 SCMutexLock(&f.m);
429c6388
AS
2546 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2547 request1, request1_len);
576ec7da
AS
2548 if (r != 0) {
2549 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2550 SCMutexUnlock(&f.m);
576ec7da
AS
2551 goto end;
2552 }
cd3e32ce 2553 SCMutexUnlock(&f.m);
576ec7da 2554 if (smtp_state->input_len != 0 ||
576ec7da
AS
2555 smtp_state->cmds_cnt != 1 ||
2556 smtp_state->cmds_idx != 0 ||
2557 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2558 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2559 printf("smtp parser in inconsistent state\n");
2560 goto end;
2561 }
2562
cd3e32ce 2563 SCMutexLock(&f.m);
429c6388
AS
2564 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
2565 reply1, reply1_len);
576ec7da
AS
2566 if (r != 0) {
2567 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2568 SCMutexUnlock(&f.m);
576ec7da
AS
2569 goto end;
2570 }
cd3e32ce 2571 SCMutexUnlock(&f.m);
576ec7da 2572 if (smtp_state->input_len != 0 ||
576ec7da
AS
2573 smtp_state->cmds_cnt != 0 ||
2574 smtp_state->cmds_idx != 0 ||
2575 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2576 printf("smtp parser in inconsistent state\n");
2577 goto end;
2578 }
2579
cd3e32ce 2580 SCMutexLock(&f.m);
429c6388
AS
2581 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2582 request2, request2_len);
576ec7da
AS
2583 if (r != 0) {
2584 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2585 SCMutexUnlock(&f.m);
576ec7da
AS
2586 goto end;
2587 }
cd3e32ce 2588 SCMutexUnlock(&f.m);
576ec7da 2589 if (smtp_state->input_len != 0 ||
576ec7da
AS
2590 smtp_state->cmds_cnt != 3 ||
2591 smtp_state->cmds_idx != 0 ||
2592 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2593 smtp_state->cmds[1] != SMTP_COMMAND_OTHER_CMD ||
2594 smtp_state->cmds[2] != SMTP_COMMAND_DATA ||
2595 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2596 printf("smtp parser in inconsistent state\n");
2597 goto end;
2598 }
2599
cd3e32ce 2600 SCMutexLock(&f.m);
429c6388
AS
2601 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
2602 reply2, reply2_len);
576ec7da
AS
2603 if (r != 0) {
2604 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2605 SCMutexUnlock(&f.m);
576ec7da
AS
2606 goto end;
2607 }
cd3e32ce 2608 SCMutexUnlock(&f.m);
576ec7da 2609 if (smtp_state->input_len != 0 ||
576ec7da
AS
2610 smtp_state->cmds_cnt != 0 ||
2611 smtp_state->cmds_idx != 0 ||
2612 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2613 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
2614 printf("smtp parser in inconsistent state\n");
2615 goto end;
2616 }
2617
2618 result = 1;
2619end:
429c6388 2620 if (alp_tctx != NULL)
fdefb65b 2621 AppLayerParserThreadCtxFree(alp_tctx);
576ec7da
AS
2622 StreamTcpFreeConfig(TRUE);
2623 FLOW_DESTROY(&f);
2624 return result;
2625}
2626
2627/*
2628 * \test Test smtp with just <LF> delimter instead of <CR><LF>.
2629 */
2630int SMTPParserTest04(void)
2631{
2632 int result = 0;
2633 Flow f;
2634 int r = 0;
2635
2636 /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
2637 uint8_t welcome_reply[] = {
2638 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
2639 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2640 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2641 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
2642 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
2643 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
2644 };
2645 uint32_t welcome_reply_len = sizeof(welcome_reply);
2646
2647 /* EHLO boo.com<CR><LF> */
2648 uint8_t request1[] = {
2649 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
2650 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2651 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2652 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
2653 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
2654 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
2655 };
2656 uint32_t request1_len = sizeof(request1);
2657
2658 TcpSession ssn;
8dbf7a0d 2659 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
576ec7da
AS
2660
2661 memset(&f, 0, sizeof(f));
2662 memset(&ssn, 0, sizeof(ssn));
2663
2664 FLOW_INITIALIZE(&f);
2665 f.protoctx = (void *)&ssn;
429c6388 2666 f.proto = IPPROTO_TCP;
576ec7da
AS
2667
2668 StreamTcpInitConfig(TRUE);
576ec7da 2669
cd3e32ce 2670 SCMutexLock(&f.m);
429c6388
AS
2671 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
2672 welcome_reply, welcome_reply_len);
576ec7da
AS
2673 if (r != 0) {
2674 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2675 SCMutexUnlock(&f.m);
576ec7da
AS
2676 goto end;
2677 }
cd3e32ce 2678 SCMutexUnlock(&f.m);
06904c90 2679 SMTPState *smtp_state = f.alstate;
576ec7da
AS
2680 if (smtp_state == NULL) {
2681 printf("no smtp state: ");
2682 goto end;
2683 }
2684 if (smtp_state->input_len != 0 ||
0d7159b5 2685 smtp_state->cmds_cnt != 0 ||
576ec7da 2686 smtp_state->cmds_idx != 0 ||
0d7159b5 2687 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
576ec7da
AS
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 request1, request1_len);
576ec7da
AS
2695 if (r != 0) {
2696 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2697 SCMutexUnlock(&f.m);
576ec7da
AS
2698 goto end;
2699 }
cd3e32ce 2700 SCMutexUnlock(&f.m);
576ec7da 2701 if (smtp_state->input_len != 0 ||
576ec7da
AS
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
2710 result = 1;
2711end:
429c6388 2712 if (alp_tctx != NULL)
fdefb65b 2713 AppLayerParserThreadCtxFree(alp_tctx);
576ec7da
AS
2714 StreamTcpFreeConfig(TRUE);
2715 FLOW_DESTROY(&f);
2716 return result;
2717}
2718
2719/*
2720 * \test Test STARTTLS fail.
2721 */
2722int SMTPParserTest05(void)
2723{
2724 int result = 0;
2725 Flow f;
2726 int r = 0;
2727
2728 /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
2729 uint8_t welcome_reply[] = {
2730 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
2731 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2732 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2733 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
2734 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
2735 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
2736 };
2737 uint32_t welcome_reply_len = sizeof(welcome_reply);
2738
2739 /* EHLO boo.com<CR><LF> */
2740 uint8_t request1[] = {
2741 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
2742 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
2743 };
2744 uint32_t request1_len = sizeof(request1);
2745 /* 250-poona_slack_vm1.localdomain<CR><LF>
2746 * 250-PIPELINING<CR><LF>
2747 * 250-SIZE 10240000<CR><LF>
2748 * 250-VRFY<CR><LF>
2749 * 250-ETRN<CR><LF>
2750 * 250-ENHANCEDSTATUSCODES<CR><LF>
2751 * 250-8BITMIME<CR><LF>
2752 * 250 DSN<CR><LF>
2753 */
2754 uint8_t reply1[] = {
2755 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
2756 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2757 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2758 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
2759 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
2760 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
2761 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
2762 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
2763 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
2764 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
2765 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
2766 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
2767 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
2768 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
2769 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
2770 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
2771 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
2772 };
2773 uint32_t reply1_len = sizeof(reply1);
2774
2775 /* STARTTLS<CR><LF> */
2776 uint8_t request2[] = {
2777 0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
2778 0x0d, 0x0a
2779 };
2780 uint32_t request2_len = sizeof(request2);
2781 /* 502 5.5.2 Error: command not recognized<CR><LF> */
2782 uint8_t reply2[] = {
2783 0x35, 0x30, 0x32, 0x20, 0x35, 0x2e, 0x35, 0x2e,
2784 0x32, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x3a,
2785 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
2786 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x63,
2787 0x6f, 0x67, 0x6e, 0x69, 0x7a, 0x65, 0x64, 0x0d,
2788 0x0a
2789 };
2790 uint32_t reply2_len = sizeof(reply2);
2791
2792 /* QUIT<CR><LF> */
2793 uint8_t request3[] = {
2794 0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
2795
2796 };
2797 uint32_t request3_len = sizeof(request3);
2798 /* 221 2.0.0 Bye<CR><LF> */
2799 uint8_t reply3[] = {
2800 0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
2801 0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
2802 };
2803 uint32_t reply3_len = sizeof(reply3);
2804
2805 TcpSession ssn;
8dbf7a0d 2806 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
576ec7da
AS
2807
2808 memset(&f, 0, sizeof(f));
2809 memset(&ssn, 0, sizeof(ssn));
2810
2811 FLOW_INITIALIZE(&f);
2812 f.protoctx = (void *)&ssn;
429c6388 2813 f.proto = IPPROTO_TCP;
576ec7da
AS
2814
2815 StreamTcpInitConfig(TRUE);
576ec7da 2816
cd3e32ce 2817 SCMutexLock(&f.m);
429c6388
AS
2818 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
2819 welcome_reply, welcome_reply_len);
576ec7da
AS
2820 if (r != 0) {
2821 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2822 SCMutexUnlock(&f.m);
576ec7da
AS
2823 goto end;
2824 }
cd3e32ce 2825 SCMutexUnlock(&f.m);
06904c90 2826 SMTPState *smtp_state = f.alstate;
576ec7da
AS
2827 if (smtp_state == NULL) {
2828 printf("no smtp state: ");
2829 goto end;
2830 }
2831 if (smtp_state->input_len != 0 ||
0d7159b5 2832 smtp_state->cmds_cnt != 0 ||
576ec7da 2833 smtp_state->cmds_idx != 0 ||
0d7159b5 2834 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
576ec7da
AS
2835 printf("smtp parser in inconsistent state\n");
2836 goto end;
2837 }
2838
cd3e32ce 2839 SCMutexLock(&f.m);
429c6388
AS
2840 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2841 request1, request1_len);
576ec7da
AS
2842 if (r != 0) {
2843 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2844 SCMutexUnlock(&f.m);
576ec7da
AS
2845 goto end;
2846 }
cd3e32ce 2847 SCMutexUnlock(&f.m);
576ec7da 2848 if (smtp_state->input_len != 0 ||
576ec7da
AS
2849 smtp_state->cmds_cnt != 1 ||
2850 smtp_state->cmds_idx != 0 ||
2851 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2852 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2853 printf("smtp parser in inconsistent state\n");
2854 goto end;
2855 }
2856
cd3e32ce 2857 SCMutexLock(&f.m);
429c6388
AS
2858 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
2859 reply1, reply1_len);
576ec7da
AS
2860 if (r != 0) {
2861 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2862 SCMutexUnlock(&f.m);
576ec7da
AS
2863 goto end;
2864 }
cd3e32ce 2865 SCMutexUnlock(&f.m);
576ec7da 2866 if (smtp_state->input_len != 0 ||
576ec7da
AS
2867 smtp_state->cmds_cnt != 0 ||
2868 smtp_state->cmds_idx != 0 ||
2869 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2870 printf("smtp parser in inconsistent state\n");
2871 goto end;
2872 }
2873
cd3e32ce 2874 SCMutexLock(&f.m);
429c6388
AS
2875 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2876 request2, request2_len);
576ec7da
AS
2877 if (r != 0) {
2878 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2879 SCMutexUnlock(&f.m);
576ec7da
AS
2880 goto end;
2881 }
cd3e32ce 2882 SCMutexUnlock(&f.m);
576ec7da 2883 if (smtp_state->input_len != 0 ||
576ec7da
AS
2884 smtp_state->cmds_cnt != 1 ||
2885 smtp_state->cmds_idx != 0 ||
2886 smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS ||
2887 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2888 printf("smtp parser in inconsistent state\n");
2889 goto end;
2890 }
2891
cd3e32ce 2892 SCMutexLock(&f.m);
429c6388
AS
2893 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
2894 reply2, reply2_len);
576ec7da
AS
2895 if (r != 0) {
2896 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2897 SCMutexUnlock(&f.m);
576ec7da
AS
2898 goto end;
2899 }
cd3e32ce 2900 SCMutexUnlock(&f.m);
576ec7da 2901 if (smtp_state->input_len != 0 ||
576ec7da
AS
2902 smtp_state->cmds_cnt != 0 ||
2903 smtp_state->cmds_idx != 0 ||
2904 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2905 printf("smtp parser in inconsistent state\n");
2906 goto end;
2907 }
2908
2909 if ((f.flags & FLOW_NOPAYLOAD_INSPECTION) ||
c1558f5a 2910 (ssn.flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) ||
576ec7da
AS
2911 (((TcpSession *)f.protoctx)->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) ||
2912 (((TcpSession *)f.protoctx)->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
2913 goto end;
2914 }
2915
cd3e32ce 2916 SCMutexLock(&f.m);
429c6388
AS
2917 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
2918 request3, request3_len);
576ec7da
AS
2919 if (r != 0) {
2920 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2921 SCMutexUnlock(&f.m);
576ec7da
AS
2922 goto end;
2923 }
cd3e32ce 2924 SCMutexUnlock(&f.m);
576ec7da 2925 if (smtp_state->input_len != 0 ||
576ec7da
AS
2926 smtp_state->cmds_cnt != 1 ||
2927 smtp_state->cmds_idx != 0 ||
2928 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2929 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2930 printf("smtp parser in inconsistent state\n");
2931 goto end;
2932 }
2933
cd3e32ce 2934 SCMutexLock(&f.m);
429c6388
AS
2935 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
2936 reply3, reply3_len);
576ec7da
AS
2937 if (r != 0) {
2938 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 2939 SCMutexUnlock(&f.m);
576ec7da
AS
2940 goto end;
2941 }
cd3e32ce 2942 SCMutexUnlock(&f.m);
576ec7da 2943 if (smtp_state->input_len != 0 ||
576ec7da
AS
2944 smtp_state->cmds_cnt != 0 ||
2945 smtp_state->cmds_idx != 0 ||
2946 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2947 printf("smtp parser in inconsistent state\n");
2948 goto end;
2949 }
2950
2951 result = 1;
2952end:
429c6388 2953 if (alp_tctx != NULL)
fdefb65b 2954 AppLayerParserThreadCtxFree(alp_tctx);
576ec7da
AS
2955 StreamTcpFreeConfig(TRUE);
2956 FLOW_DESTROY(&f);
2957 return result;
2958}
2959
d3ca65de
AS
2960/**
2961 * \test Test multiple DATA commands(full mail transactions).
2962 */
2963int SMTPParserTest06(void)
2964{
2965 int result = 0;
2966 Flow f;
2967 int r = 0;
2968
2969 uint8_t welcome_reply[] = {
2970 0x32, 0x32, 0x30, 0x20, 0x62, 0x61, 0x79, 0x30,
2971 0x2d, 0x6d, 0x63, 0x36, 0x2d, 0x66, 0x31, 0x30,
2972 0x2e, 0x62, 0x61, 0x79, 0x30, 0x2e, 0x68, 0x6f,
2973 0x74, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f,
2974 0x6d, 0x20, 0x53, 0x65, 0x6e, 0x64, 0x69, 0x6e,
2975 0x67, 0x20, 0x75, 0x6e, 0x73, 0x6f, 0x6c, 0x69,
2976 0x63, 0x69, 0x74, 0x65, 0x64, 0x20, 0x63, 0x6f,
2977 0x6d, 0x6d, 0x65, 0x72, 0x63, 0x69, 0x61, 0x6c,
2978 0x20, 0x6f, 0x72, 0x20, 0x62, 0x75, 0x6c, 0x6b,
2979 0x20, 0x65, 0x2d, 0x6d, 0x61, 0x69, 0x6c, 0x20,
2980 0x74, 0x6f, 0x20, 0x4d, 0x69, 0x63, 0x72, 0x6f,
2981 0x73, 0x6f, 0x66, 0x74, 0x27, 0x73, 0x20, 0x63,
2982 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x20,
2983 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20,
2984 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x68, 0x69,
2985 0x62, 0x69, 0x74, 0x65, 0x64, 0x2e, 0x20, 0x4f,
2986 0x74, 0x68, 0x65, 0x72, 0x20, 0x72, 0x65, 0x73,
2987 0x74, 0x72, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e,
2988 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x66, 0x6f,
2989 0x75, 0x6e, 0x64, 0x20, 0x61, 0x74, 0x20, 0x68,
2990 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x72,
2991 0x69, 0x76, 0x61, 0x63, 0x79, 0x2e, 0x6d, 0x73,
2992 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x41, 0x6e,
2993 0x74, 0x69, 0x2d, 0x73, 0x70, 0x61, 0x6d, 0x2f,
2994 0x2e, 0x20, 0x56, 0x69, 0x6f, 0x6c, 0x61, 0x74,
2995 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x77, 0x69, 0x6c,
2996 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74,
2997 0x20, 0x69, 0x6e, 0x20, 0x75, 0x73, 0x65, 0x20,
2998 0x6f, 0x66, 0x20, 0x65, 0x71, 0x75, 0x69, 0x70,
2999 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x63,
3000 0x61, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20,
3001 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e,
3002 0x69, 0x61, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6f,
3003 0x74, 0x68, 0x65, 0x72, 0x20, 0x73, 0x74, 0x61,
3004 0x74, 0x65, 0x73, 0x2e, 0x20, 0x46, 0x72, 0x69,
3005 0x2c, 0x20, 0x31, 0x36, 0x20, 0x46, 0x65, 0x62,
3006 0x20, 0x32, 0x30, 0x30, 0x37, 0x20, 0x30, 0x35,
3007 0x3a, 0x30, 0x33, 0x3a, 0x32, 0x33, 0x20, 0x2d,
3008 0x30, 0x38, 0x30, 0x30, 0x20, 0x0d, 0x0a
3009 };
3010 uint32_t welcome_reply_len = sizeof(welcome_reply);
3011
3012 uint8_t request1[] = {
3013 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x45, 0x58, 0x43,
3014 0x48, 0x41, 0x4e, 0x47, 0x45, 0x32, 0x2e, 0x63,
3015 0x67, 0x63, 0x65, 0x6e, 0x74, 0x2e, 0x6d, 0x69,
3016 0x61, 0x6d, 0x69, 0x2e, 0x65, 0x64, 0x75, 0x0d,
3017 0x0a
3018 };
3019 uint32_t request1_len = sizeof(request1);
3020
3021 uint8_t reply1[] = {
3022 0x32, 0x35, 0x30, 0x2d, 0x62, 0x61, 0x79, 0x30,
3023 0x2d, 0x6d, 0x63, 0x36, 0x2d, 0x66, 0x31, 0x30,
3024 0x2e, 0x62, 0x61, 0x79, 0x30, 0x2e, 0x68, 0x6f,
3025 0x74, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f,
3026 0x6d, 0x20, 0x28, 0x33, 0x2e, 0x33, 0x2e, 0x31,
3027 0x2e, 0x34, 0x29, 0x20, 0x48, 0x65, 0x6c, 0x6c,
3028 0x6f, 0x20, 0x5b, 0x31, 0x32, 0x39, 0x2e, 0x31,
3029 0x37, 0x31, 0x2e, 0x33, 0x32, 0x2e, 0x35, 0x39,
3030 0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53,
3031 0x49, 0x5a, 0x45, 0x20, 0x32, 0x39, 0x36, 0x39,
3032 0x36, 0x30, 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35,
3033 0x30, 0x2d, 0x50, 0x49, 0x50, 0x45, 0x4c, 0x49,
3034 0x4e, 0x49, 0x4e, 0x47, 0x0d, 0x0a, 0x32, 0x35,
3035 0x30, 0x2d, 0x38, 0x62, 0x69, 0x74, 0x6d, 0x69,
3036 0x6d, 0x65, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3037 0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x4d, 0x49,
3038 0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3039 0x43, 0x48, 0x55, 0x4e, 0x4b, 0x49, 0x4e, 0x47,
3040 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x41, 0x55,
3041 0x54, 0x48, 0x20, 0x4c, 0x4f, 0x47, 0x49, 0x4e,
3042 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x41, 0x55,
3043 0x54, 0x48, 0x3d, 0x4c, 0x4f, 0x47, 0x49, 0x4e,
3044 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20, 0x4f, 0x4b,
3045 0x0d, 0x0a
3046 };
3047 uint32_t reply1_len = sizeof(reply1);
3048
3049 /* MAIL FROM:asdff@asdf.com<CR><LF> */
3050 uint8_t request2[] = {
3051 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
3052 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
3053 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
3054 0x0d, 0x0a
3055 };
3056 uint32_t request2_len = sizeof(request2);
3057 /* 250 2.1.0 Ok<CR><LF> */
3058 uint8_t reply2[] = {
3059 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
3060 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
3061 };
3062 uint32_t reply2_len = sizeof(reply2);
3063
3064 /* RCPT TO:bimbs@gmail.com<CR><LF> */
3065 uint8_t request3[] = {
3066 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
3067 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
3068 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
3069 0x0a
3070 };
3071 uint32_t request3_len = sizeof(request3);
3072 /* 250 2.1.5 Ok<CR><LF> */
3073 uint8_t reply3[] = {
3074 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
3075 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
3076 };
3077 uint32_t reply3_len = sizeof(reply3);
3078
3079 /* BDAT 51<CR><LF> */
3080 uint8_t request4[] = {
3081 0x42, 0x44, 0x41, 0x54, 0x20, 0x35, 0x31, 0x0d,
3082 0x0a,
3083 };
3084 uint32_t request4_len = sizeof(request4);
3085
3086 uint8_t request5[] = {
3087 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
3088 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
3089 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
3090 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x0d, 0x0a,
3091 };
3092 uint32_t request5_len = sizeof(request5);
3093
3094 uint8_t request6[] = {
3095 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
3096 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
3097 0x66, 0x0d, 0x0a,
3098 };
561630d8 3099 uint32_t request6_len = sizeof(request6);
d3ca65de
AS
3100
3101 TcpSession ssn;
8dbf7a0d 3102 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
d3ca65de
AS
3103
3104 memset(&f, 0, sizeof(f));
3105 memset(&ssn, 0, sizeof(ssn));
3106
3107 FLOW_INITIALIZE(&f);
3108 f.protoctx = (void *)&ssn;
429c6388 3109 f.proto = IPPROTO_TCP;
d3ca65de
AS
3110
3111 StreamTcpInitConfig(TRUE);
d3ca65de 3112
cd3e32ce 3113 SCMutexLock(&f.m);
429c6388
AS
3114 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
3115 welcome_reply, welcome_reply_len);
d3ca65de
AS
3116 if (r != 0) {
3117 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3118 SCMutexUnlock(&f.m);
d3ca65de
AS
3119 goto end;
3120 }
cd3e32ce 3121 SCMutexUnlock(&f.m);
06904c90 3122 SMTPState *smtp_state = f.alstate;
d3ca65de
AS
3123 if (smtp_state == NULL) {
3124 printf("no smtp state: ");
3125 goto end;
3126 }
3127 if (smtp_state->input_len != 0 ||
0d7159b5 3128 smtp_state->cmds_cnt != 0 ||
d3ca65de 3129 smtp_state->cmds_idx != 0 ||
0d7159b5 3130 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
d3ca65de
AS
3131 printf("smtp parser in inconsistent state\n");
3132 goto end;
3133 }
3134
cd3e32ce 3135 SCMutexLock(&f.m);
429c6388
AS
3136 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3137 request1, request1_len);
d3ca65de
AS
3138 if (r != 0) {
3139 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3140 SCMutexUnlock(&f.m);
d3ca65de
AS
3141 goto end;
3142 }
cd3e32ce 3143 SCMutexUnlock(&f.m);
d3ca65de
AS
3144 if (smtp_state->input_len != 0 ||
3145 smtp_state->cmds_cnt != 1 ||
3146 smtp_state->cmds_idx != 0 ||
3147 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3148 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
3149 printf("smtp parser in inconsistent state\n");
3150 goto end;
3151 }
3152
cd3e32ce 3153 SCMutexLock(&f.m);
429c6388
AS
3154 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
3155 reply1, reply1_len);
d3ca65de
AS
3156 if (r != 0) {
3157 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3158 SCMutexUnlock(&f.m);
d3ca65de
AS
3159 goto end;
3160 }
cd3e32ce 3161 SCMutexUnlock(&f.m);
d3ca65de
AS
3162 if (smtp_state->input_len != 0 ||
3163 smtp_state->cmds_cnt != 0 ||
3164 smtp_state->cmds_idx != 0 ||
3165 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
3166 printf("smtp parser in inconsistent state\n");
3167 goto end;
3168 }
3169
cd3e32ce 3170 SCMutexLock(&f.m);
429c6388
AS
3171 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3172 request2, request2_len);
d3ca65de
AS
3173 if (r != 0) {
3174 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3175 SCMutexUnlock(&f.m);
d3ca65de
AS
3176 goto end;
3177 }
cd3e32ce 3178 SCMutexUnlock(&f.m);
d3ca65de
AS
3179 if (smtp_state->input_len != 0 ||
3180 smtp_state->cmds_cnt != 1 ||
3181 smtp_state->cmds_idx != 0 ||
3182 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3183 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
3184 printf("smtp parser in inconsistent state\n");
3185 goto end;
3186 }
3187
cd3e32ce 3188 SCMutexLock(&f.m);
429c6388
AS
3189 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
3190 reply2, reply2_len);
d3ca65de
AS
3191 if (r != 0) {
3192 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3193 SCMutexUnlock(&f.m);
d3ca65de
AS
3194 goto end;
3195 }
cd3e32ce 3196 SCMutexUnlock(&f.m);
d3ca65de
AS
3197 if (smtp_state->input_len != 0 ||
3198 smtp_state->cmds_cnt != 0 ||
3199 smtp_state->cmds_idx != 0 ||
3200 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
3201 printf("smtp parser in inconsistent state\n");
3202 goto end;
3203 }
3204
cd3e32ce 3205 SCMutexLock(&f.m);
429c6388
AS
3206 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3207 request3, request3_len);
d3ca65de
AS
3208 if (r != 0) {
3209 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3210 SCMutexUnlock(&f.m);
d3ca65de
AS
3211 goto end;
3212 }
cd3e32ce 3213 SCMutexUnlock(&f.m);
d3ca65de
AS
3214 if (smtp_state->input_len != 0 ||
3215 smtp_state->cmds_cnt != 1 ||
3216 smtp_state->cmds_idx != 0 ||
3217 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3218 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
3219 printf("smtp parser in inconsistent state\n");
3220 goto end;
3221 }
3222
cd3e32ce 3223 SCMutexLock(&f.m);
429c6388
AS
3224 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
3225 reply3, reply3_len);
d3ca65de
AS
3226 if (r != 0) {
3227 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3228 SCMutexUnlock(&f.m);
d3ca65de
AS
3229 goto end;
3230 }
cd3e32ce 3231 SCMutexUnlock(&f.m);
d3ca65de
AS
3232 if (smtp_state->input_len != 0 ||
3233 smtp_state->cmds_cnt != 0 ||
3234 smtp_state->cmds_idx != 0 ||
3235 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
3236 printf("smtp parser in inconsistent state\n");
3237 goto end;
3238 }
3239
cd3e32ce 3240 SCMutexLock(&f.m);
429c6388
AS
3241 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3242 request4, request4_len);
d3ca65de
AS
3243 if (r != 0) {
3244 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3245 SCMutexUnlock(&f.m);
d3ca65de
AS
3246 goto end;
3247 }
cd3e32ce 3248 SCMutexUnlock(&f.m);
d3ca65de
AS
3249 if (smtp_state->input_len != 0 ||
3250 smtp_state->cmds_cnt != 1 ||
3251 smtp_state->cmds_idx != 0 ||
3252 smtp_state->cmds[0] != SMTP_COMMAND_BDAT ||
3253 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
3254 SMTP_PARSER_STATE_COMMAND_DATA_MODE) ||
3255 smtp_state->bdat_chunk_len != 51 ||
3256 smtp_state->bdat_chunk_idx != 0) {
3257 printf("smtp parser in inconsistent state\n");
3258 goto end;
3259 }
3260
cd3e32ce 3261 SCMutexLock(&f.m);
429c6388
AS
3262 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3263 request5, request5_len);
d3ca65de
AS
3264 if (r != 0) {
3265 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3266 SCMutexUnlock(&f.m);
d3ca65de
AS
3267 goto end;
3268 }
cd3e32ce 3269 SCMutexUnlock(&f.m);
d3ca65de
AS
3270 if (smtp_state->input_len != 0 ||
3271 smtp_state->cmds_cnt != 1 ||
3272 smtp_state->cmds_idx != 0 ||
3273 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
3274 SMTP_PARSER_STATE_COMMAND_DATA_MODE) ||
3275 smtp_state->bdat_chunk_len != 51 ||
3276 smtp_state->bdat_chunk_idx != 32) {
3277 printf("smtp parser in inconsistent state\n");
3278 goto end;
3279 }
3280
cd3e32ce 3281 SCMutexLock(&f.m);
429c6388
AS
3282 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3283 request6, request6_len);
d3ca65de
AS
3284 if (r != 0) {
3285 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3286 SCMutexUnlock(&f.m);
d3ca65de
AS
3287 goto end;
3288 }
cd3e32ce 3289 SCMutexUnlock(&f.m);
d3ca65de
AS
3290 if (smtp_state->input_len != 0 ||
3291 smtp_state->cmds_cnt != 1 ||
3292 smtp_state->cmds_idx != 0 ||
3293 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN ||
3294 smtp_state->bdat_chunk_len != 51 ||
3295 smtp_state->bdat_chunk_idx != 51) {
3296 printf("smtp parser in inconsistent state\n");
3297 goto end;
3298 }
3299
3300 result = 1;
3301end:
429c6388 3302 if (alp_tctx != NULL)
fdefb65b 3303 AppLayerParserThreadCtxFree(alp_tctx);
d3ca65de
AS
3304 StreamTcpFreeConfig(TRUE);
3305 FLOW_DESTROY(&f);
3306 return result;
3307}
3308
4a6908d3
AS
3309/*
3310 * \test Test retrieving lines when frag'ed.
3311 */
3312int SMTPParserTest07(void)
3313{
3314 int result = 0;
3315 Flow f;
3316 int r = 0;
3317
3318 const char *request1_str = "EHLO boo.com";
3319 /* EHLO boo.com<CR> */
3320 uint8_t request1_1[] = {
3321 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3322 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
3323 };
3324 int32_t request1_1_len = sizeof(request1_1);
3325
3326 /* <LF> */
3327 uint8_t request1_2[] = {
3328 0x0a
3329 };
3330 int32_t request1_2_len = sizeof(request1_2);
3331
3332 /* EHLO boo.com<CR><LF> */
3333 uint8_t request2[] = {
3334 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3335 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3336 };
3337 int32_t request2_len = sizeof(request2);
3338
3339 TcpSession ssn;
8dbf7a0d 3340 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
4a6908d3
AS
3341
3342 memset(&f, 0, sizeof(f));
3343 memset(&ssn, 0, sizeof(ssn));
3344
3345 FLOW_INITIALIZE(&f);
3346 f.protoctx = (void *)&ssn;
429c6388 3347 f.proto = IPPROTO_TCP;
4a6908d3
AS
3348
3349 StreamTcpInitConfig(TRUE);
4a6908d3 3350
cd3e32ce 3351 SCMutexLock(&f.m);
429c6388
AS
3352 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3353 request1_1, request1_1_len);
4a6908d3
AS
3354 if (r != 0) {
3355 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3356 SCMutexUnlock(&f.m);
4a6908d3
AS
3357 goto end;
3358 }
cd3e32ce 3359 SCMutexUnlock(&f.m);
bf24272c 3360 SMTPState *smtp_state = f.alstate;
4a6908d3
AS
3361 if (smtp_state == NULL) {
3362 printf("no smtp state: ");
3363 goto end;
3364 }
3365 if (smtp_state->current_line != NULL ||
3366 smtp_state->current_line_len != 0 ||
3367 smtp_state->ts_current_line_db != 1 ||
3368 smtp_state->ts_db == NULL ||
3369 smtp_state->ts_db_len != request1_1_len ||
3370 memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) {
3371 printf("smtp parser in inconsistent state\n");
3372 goto end;
3373 }
3374
cd3e32ce 3375 SCMutexLock(&f.m);
429c6388
AS
3376 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3377 request1_2, request1_2_len);
4a6908d3
AS
3378 if (r != 0) {
3379 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3380 SCMutexUnlock(&f.m);
4a6908d3
AS
3381 goto end;
3382 }
cd3e32ce 3383 SCMutexUnlock(&f.m);
4a6908d3
AS
3384 if (smtp_state->ts_current_line_db != 1 ||
3385 smtp_state->ts_db == NULL ||
3386 smtp_state->ts_db_len != (int32_t)strlen(request1_str) ||
3387 memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 ||
3388 smtp_state->current_line != smtp_state->ts_db ||
3389 smtp_state->current_line_len != smtp_state->ts_db_len) {
3390 printf("smtp parser in inconsistent state\n");
3391 goto end;
3392 }
3393
cd3e32ce 3394 SCMutexLock(&f.m);
429c6388
AS
3395 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3396 request2, request2_len);
4a6908d3
AS
3397 if (r != 0) {
3398 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3399 SCMutexUnlock(&f.m);
4a6908d3
AS
3400 goto end;
3401 }
cd3e32ce 3402 SCMutexUnlock(&f.m);
4a6908d3
AS
3403 if (smtp_state->ts_current_line_db != 0 ||
3404 smtp_state->ts_db != NULL ||
3405 smtp_state->ts_db_len != 0 ||
3406 smtp_state->current_line == NULL ||
3407 smtp_state->current_line_len != (int32_t)strlen(request1_str) ||
3408 memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) {
3409 printf("smtp parser in inconsistent state\n");
3410 goto end;
3411 }
3412
3413 result = 1;
3414end:
429c6388 3415 if (alp_tctx != NULL)
fdefb65b 3416 AppLayerParserThreadCtxFree(alp_tctx);
4a6908d3
AS
3417 StreamTcpFreeConfig(TRUE);
3418 FLOW_DESTROY(&f);
3419 return result;
3420}
3421
3422/*
3423 * \test Test retrieving lines when frag'ed.
3424 */
3425int SMTPParserTest08(void)
3426{
3427 int result = 0;
3428 Flow f;
3429 int r = 0;
3430
3431 const char *request1_str = "EHLO boo.com";
3432 /* EHLO boo.com */
3433 uint8_t request1_1[] = {
3434 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3435 0x2e, 0x63, 0x6f, 0x6d,
3436 };
3437 int32_t request1_1_len = sizeof(request1_1);
3438
3439 /* <CR><LF> */
3440 uint8_t request1_2[] = {
3441 0x0d, 0x0a
3442 };
3443 int32_t request1_2_len = sizeof(request1_2);
3444
3445 /* EHLO boo.com<CR><LF> */
3446 uint8_t request2[] = {
3447 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3448 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3449 };
3450 int32_t request2_len = sizeof(request2);
3451
3452 TcpSession ssn;
8dbf7a0d 3453 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
4a6908d3
AS
3454
3455 memset(&f, 0, sizeof(f));
3456 memset(&ssn, 0, sizeof(ssn));
3457
3458 FLOW_INITIALIZE(&f);
3459 f.protoctx = (void *)&ssn;
429c6388 3460 f.proto = IPPROTO_TCP;
4a6908d3
AS
3461
3462 StreamTcpInitConfig(TRUE);
4a6908d3 3463
cd3e32ce 3464 SCMutexLock(&f.m);
429c6388
AS
3465 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3466 request1_1, request1_1_len);
4a6908d3
AS
3467 if (r != 0) {
3468 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3469 SCMutexUnlock(&f.m);
4a6908d3
AS
3470 goto end;
3471 }
cd3e32ce 3472 SCMutexUnlock(&f.m);
bf24272c 3473 SMTPState *smtp_state = f.alstate;
4a6908d3
AS
3474 if (smtp_state == NULL) {
3475 printf("no smtp state: ");
3476 goto end;
3477 }
3478 if (smtp_state->current_line != NULL ||
3479 smtp_state->current_line_len != 0 ||
3480 smtp_state->ts_current_line_db != 1 ||
3481 smtp_state->ts_db == NULL ||
3482 smtp_state->ts_db_len != request1_1_len ||
3483 memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) {
3484 printf("smtp parser in inconsistent state\n");
3485 goto end;
3486 }
3487
cd3e32ce 3488 SCMutexLock(&f.m);
429c6388
AS
3489 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3490 request1_2, request1_2_len);
4a6908d3
AS
3491 if (r != 0) {
3492 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3493 SCMutexUnlock(&f.m);
4a6908d3
AS
3494 goto end;
3495 }
cd3e32ce 3496 SCMutexUnlock(&f.m);
4a6908d3
AS
3497 if (smtp_state->ts_current_line_db != 1 ||
3498 smtp_state->ts_db == NULL ||
3499 smtp_state->ts_db_len != (int32_t)strlen(request1_str) ||
3500 memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 ||
3501 smtp_state->current_line != smtp_state->ts_db ||
3502 smtp_state->current_line_len != smtp_state->ts_db_len) {
3503 printf("smtp parser in inconsistent state\n");
3504 goto end;
3505 }
3506
cd3e32ce 3507 SCMutexLock(&f.m);
429c6388
AS
3508 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3509 request2, request2_len);
4a6908d3
AS
3510 if (r != 0) {
3511 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3512 SCMutexUnlock(&f.m);
4a6908d3
AS
3513 goto end;
3514 }
cd3e32ce 3515 SCMutexUnlock(&f.m);
4a6908d3
AS
3516 if (smtp_state->ts_current_line_db != 0 ||
3517 smtp_state->ts_db != NULL ||
3518 smtp_state->ts_db_len != 0 ||
3519 smtp_state->current_line == NULL ||
3520 smtp_state->current_line_len != (int32_t)strlen(request1_str) ||
3521 memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) {
3522 printf("smtp parser in inconsistent state\n");
3523 goto end;
3524 }
3525
3526 result = 1;
3527end:
429c6388 3528 if (alp_tctx != NULL)
fdefb65b 3529 AppLayerParserThreadCtxFree(alp_tctx);
4a6908d3
AS
3530 StreamTcpFreeConfig(TRUE);
3531 FLOW_DESTROY(&f);
3532 return result;
3533}
3534
3535/*
3536 * \test Test retrieving lines when frag'ed.
3537 */
3538int SMTPParserTest09(void)
3539{
3540 int result = 0;
3541 Flow f;
3542 int r = 0;
3543
3544 const char *request1_str = "EHLO boo.com";
3545 /* EHLO boo. */
3546 uint8_t request1_1[] = {
3547 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3548 0x2e,
3549 };
3550 int32_t request1_1_len = sizeof(request1_1);
3551
3552 /* com<CR><LF> */
3553 uint8_t request1_2[] = {
3554 0x63, 0x6f, 0x6d, 0x0d, 0x0a
3555 };
3556 int32_t request1_2_len = sizeof(request1_2);
3557
3558 /* EHLO boo.com<CR><LF> */
3559 uint8_t request2[] = {
3560 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3561 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3562 };
3563 int32_t request2_len = sizeof(request2);
3564
3565 TcpSession ssn;
8dbf7a0d 3566 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
4a6908d3
AS
3567
3568 memset(&f, 0, sizeof(f));
3569 memset(&ssn, 0, sizeof(ssn));
3570
3571 FLOW_INITIALIZE(&f);
3572 f.protoctx = (void *)&ssn;
429c6388 3573 f.proto = IPPROTO_TCP;
4a6908d3
AS
3574
3575 StreamTcpInitConfig(TRUE);
4a6908d3 3576
cd3e32ce 3577 SCMutexLock(&f.m);
429c6388
AS
3578 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3579 request1_1, request1_1_len);
4a6908d3
AS
3580 if (r != 0) {
3581 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3582 SCMutexUnlock(&f.m);
4a6908d3
AS
3583 goto end;
3584 }
cd3e32ce 3585 SCMutexUnlock(&f.m);
bf24272c 3586 SMTPState *smtp_state = f.alstate;
4a6908d3
AS
3587 if (smtp_state == NULL) {
3588 printf("no smtp state: ");
3589 goto end;
3590 }
3591 if (smtp_state->current_line != NULL ||
3592 smtp_state->current_line_len != 0 ||
3593 smtp_state->ts_current_line_db != 1 ||
3594 smtp_state->ts_db == NULL ||
3595 smtp_state->ts_db_len != request1_1_len ||
3596 memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) {
3597 printf("smtp parser in inconsistent state\n");
3598 goto end;
3599 }
3600
cd3e32ce 3601 SCMutexLock(&f.m);
429c6388
AS
3602 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3603 request1_2, request1_2_len);
4a6908d3
AS
3604 if (r != 0) {
3605 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3606 SCMutexUnlock(&f.m);
4a6908d3
AS
3607 goto end;
3608 }
cd3e32ce 3609 SCMutexUnlock(&f.m);
4a6908d3
AS
3610 if (smtp_state->ts_current_line_db != 1 ||
3611 smtp_state->ts_db == NULL ||
3612 smtp_state->ts_db_len != (int32_t)strlen(request1_str) ||
3613 memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 ||
3614 smtp_state->current_line != smtp_state->ts_db ||
3615 smtp_state->current_line_len != smtp_state->ts_db_len) {
3616 printf("smtp parser in inconsistent state\n");
3617 goto end;
3618 }
3619
cd3e32ce 3620 SCMutexLock(&f.m);
429c6388
AS
3621 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3622 request2, request2_len);
4a6908d3
AS
3623 if (r != 0) {
3624 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3625 SCMutexUnlock(&f.m);
4a6908d3
AS
3626 goto end;
3627 }
cd3e32ce 3628 SCMutexUnlock(&f.m);
4a6908d3
AS
3629 if (smtp_state->ts_current_line_db != 0 ||
3630 smtp_state->ts_db != NULL ||
3631 smtp_state->ts_db_len != 0 ||
3632 smtp_state->current_line == NULL ||
3633 smtp_state->current_line_len != (int32_t)strlen(request1_str) ||
3634 memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) {
3635 printf("smtp parser in inconsistent state\n");
3636 goto end;
3637 }
3638
3639 result = 1;
3640end:
429c6388 3641 if (alp_tctx != NULL)
fdefb65b 3642 AppLayerParserThreadCtxFree(alp_tctx);
4a6908d3
AS
3643 StreamTcpFreeConfig(TRUE);
3644 FLOW_DESTROY(&f);
3645 return result;
3646}
3647
3648/*
3649 * \test Test retrieving lines when frag'ed.
3650 */
3651int SMTPParserTest10(void)
3652{
3653 int result = 0;
3654 Flow f;
3655 int r = 0;
3656
3657 const char *request1_str = "";
3658 /* EHLO boo. */
3659 uint8_t request1_1[] = {
3660 0x0d,
3661 };
3662 int32_t request1_1_len = sizeof(request1_1);
3663
3664 /* com<CR><LF> */
3665 uint8_t request1_2[] = {
3666 0x0a,
3667 };
3668 int32_t request1_2_len = sizeof(request1_2);
3669
3670 const char *request2_str = "EHLO boo.com";
3671 /* EHLO boo.com<CR><LF> */
3672 uint8_t request2[] = {
3673 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3674 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3675 };
3676 int32_t request2_len = sizeof(request2);
3677
3678 TcpSession ssn;
8dbf7a0d 3679 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
4a6908d3
AS
3680
3681 memset(&f, 0, sizeof(f));
3682 memset(&ssn, 0, sizeof(ssn));
3683
3684 FLOW_INITIALIZE(&f);
3685 f.protoctx = (void *)&ssn;
429c6388 3686 f.proto = IPPROTO_TCP;
4a6908d3
AS
3687
3688 StreamTcpInitConfig(TRUE);
4a6908d3 3689
cd3e32ce 3690 SCMutexLock(&f.m);
429c6388
AS
3691 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3692 request1_1, request1_1_len);
4a6908d3
AS
3693 if (r != 0) {
3694 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3695 SCMutexUnlock(&f.m);
4a6908d3
AS
3696 goto end;
3697 }
cd3e32ce 3698 SCMutexUnlock(&f.m);
bf24272c 3699 SMTPState *smtp_state = f.alstate;
4a6908d3
AS
3700 if (smtp_state == NULL) {
3701 printf("no smtp state: ");
3702 goto end;
3703 }
3704 if (smtp_state->current_line != NULL ||
3705 smtp_state->current_line_len != 0 ||
3706 smtp_state->ts_current_line_db != 1 ||
3707 smtp_state->ts_db == NULL ||
3708 smtp_state->ts_db_len != request1_1_len ||
3709 memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) {
3710 printf("smtp parser in inconsistent state\n");
3711 goto end;
3712 }
3713
cd3e32ce 3714 SCMutexLock(&f.m);
429c6388
AS
3715 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3716 request1_2, request1_2_len);
4a6908d3
AS
3717 if (r != 0) {
3718 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3719 SCMutexUnlock(&f.m);
4a6908d3
AS
3720 goto end;
3721 }
cd3e32ce 3722 SCMutexUnlock(&f.m);
4a6908d3
AS
3723 if (smtp_state->ts_current_line_db != 1 ||
3724 smtp_state->ts_db == NULL ||
3725 smtp_state->ts_db_len != (int32_t)strlen(request1_str) ||
3726 memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 ||
3727 smtp_state->current_line != smtp_state->ts_db ||
3728 smtp_state->current_line_len != smtp_state->ts_db_len) {
3729 printf("smtp parser in inconsistent state\n");
3730 goto end;
3731 }
3732
cd3e32ce 3733 SCMutexLock(&f.m);
429c6388
AS
3734 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3735 request2, request2_len);
4a6908d3
AS
3736 if (r != 0) {
3737 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3738 SCMutexUnlock(&f.m);
4a6908d3
AS
3739 goto end;
3740 }
cd3e32ce 3741 SCMutexUnlock(&f.m);
4a6908d3
AS
3742 if (smtp_state->ts_current_line_db != 0 ||
3743 smtp_state->ts_db != NULL ||
3744 smtp_state->ts_db_len != 0 ||
3745 smtp_state->current_line == NULL ||
3746 smtp_state->current_line_len != (int32_t)strlen(request2_str) ||
3747 memcmp(smtp_state->current_line, request2_str, strlen(request2_str)) != 0) {
3748 printf("smtp parser in inconsistent state\n");
3749 goto end;
3750 }
3751
3752 result = 1;
3753end:
429c6388 3754 if (alp_tctx != NULL)
fdefb65b 3755 AppLayerParserThreadCtxFree(alp_tctx);
4a6908d3
AS
3756 StreamTcpFreeConfig(TRUE);
3757 FLOW_DESTROY(&f);
3758 return result;
3759}
3760
3761/*
3762 * \test Test retrieving lines when frag'ed.
3763 */
3764int SMTPParserTest11(void)
3765{
3766 int result = 0;
3767 Flow f;
3768 int r = 0;
3769
3770 const char *request1_str = "";
3771 /* EHLO boo. */
3772 uint8_t request1[] = {
3773 0x0a,
3774 };
3775 int32_t request1_len = sizeof(request1);
3776
3777 const char *request2_str = "EHLO boo.com";
3778 /* EHLO boo.com<CR><LF> */
3779 uint8_t request2[] = {
3780 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3781 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3782 };
3783 int32_t request2_len = sizeof(request2);
3784
3785 TcpSession ssn;
8dbf7a0d 3786 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
4a6908d3
AS
3787
3788 memset(&f, 0, sizeof(f));
3789 memset(&ssn, 0, sizeof(ssn));
3790
3791 FLOW_INITIALIZE(&f);
3792 f.protoctx = (void *)&ssn;
429c6388 3793 f.proto = IPPROTO_TCP;
4a6908d3
AS
3794
3795 StreamTcpInitConfig(TRUE);
4a6908d3 3796
cd3e32ce 3797 SCMutexLock(&f.m);
429c6388
AS
3798 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3799 request1, request1_len);
4a6908d3
AS
3800 if (r != 0) {
3801 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3802 SCMutexUnlock(&f.m);
4a6908d3
AS
3803 goto end;
3804 }
cd3e32ce 3805 SCMutexUnlock(&f.m);
bf24272c 3806 SMTPState *smtp_state = f.alstate;
4a6908d3
AS
3807 if (smtp_state == NULL) {
3808 printf("no smtp state: ");
3809 goto end;
3810 }
3811 if (smtp_state->current_line == NULL ||
3812 smtp_state->current_line_len != 0 ||
3813 smtp_state->ts_current_line_db == 1 ||
3814 smtp_state->ts_db != NULL ||
3815 smtp_state->ts_db_len != 0 ||
3816 memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) {
3817 printf("smtp parser in inconsistent state\n");
3818 goto end;
3819 }
3820
cd3e32ce 3821 SCMutexLock(&f.m);
429c6388
AS
3822 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
3823 request2, request2_len);
4a6908d3
AS
3824 if (r != 0) {
3825 printf("smtp check returned %" PRId32 ", expected 0: ", r);
cd3e32ce 3826 SCMutexUnlock(&f.m);
4a6908d3
AS
3827 goto end;
3828 }
cd3e32ce 3829 SCMutexUnlock(&f.m);
4a6908d3
AS
3830 if (smtp_state->ts_current_line_db != 0 ||
3831 smtp_state->ts_db != NULL ||
3832 smtp_state->ts_db_len != 0 ||
3833 smtp_state->current_line == NULL ||
3834 smtp_state->current_line_len != (int32_t)strlen(request2_str) ||
3835 memcmp(smtp_state->current_line, request2_str, strlen(request2_str)) != 0) {
3836 printf("smtp parser in inconsistent state\n");
3837 goto end;
3838 }
3839
3840 result = 1;
3841end:
429c6388 3842 if (alp_tctx != NULL)
fdefb65b 3843 AppLayerParserThreadCtxFree(alp_tctx);
4a6908d3
AS
3844 StreamTcpFreeConfig(TRUE);
3845 FLOW_DESTROY(&f);
3846 return result;
3847}
3848
5311cd48
AS
3849int SMTPParserTest12(void)
3850{
3851 int result = 0;
3852 Signature *s = NULL;
3853 ThreadVars th_v;
3854 Packet *p = NULL;
3855 Flow f;
3856 TcpSession ssn;
3857 DetectEngineThreadCtx *det_ctx = NULL;
3858 DetectEngineCtx *de_ctx = NULL;
3859 SMTPState *smtp_state = NULL;
3860 int r = 0;
3861
3862 /* EHLO boo.com<CR><LF> */
3863 uint8_t request1[] = {
3864 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3865 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3866 };
3867 int32_t request1_len = sizeof(request1);
3868
3869 /* 388<CR><LF>
3870 */
3871 uint8_t reply1[] = {
3872 0x31, 0x38, 0x38, 0x0d, 0x0a,
3873 };
3874 uint32_t reply1_len = sizeof(reply1);
3875
8dbf7a0d 3876 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
429c6388 3877
5311cd48
AS
3878 memset(&th_v, 0, sizeof(th_v));
3879 memset(&f, 0, sizeof(f));
3880 memset(&ssn, 0, sizeof(ssn));
3881
3882 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
3883
3884 FLOW_INITIALIZE(&f);
3885 f.protoctx = (void *)&ssn;
429c6388 3886 f.proto = IPPROTO_TCP;
5311cd48
AS
3887 p->flow = &f;
3888 p->flowflags |= FLOW_PKT_TOSERVER;
3889 p->flowflags |= FLOW_PKT_ESTABLISHED;
3890 p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
3891 f.alproto = ALPROTO_SMTP;
3892
3893 StreamTcpInitConfig(TRUE);
5311cd48
AS
3894
3895 de_ctx = DetectEngineCtxInit();
3896 if (de_ctx == NULL)
3897 goto end;
3898
3899 de_ctx->flags |= DE_QUIET;
3900
3901 s = DetectEngineAppendSig(de_ctx,"alert tcp any any -> any any "
3902 "(msg:\"SMTP event handling\"; "
7fa22e84 3903 "app-layer-event: smtp.invalid_reply; "
5311cd48
AS
3904 "sid:1;)");
3905 if (s == NULL)
3906 goto end;
3907
3908 SigGroupBuild(de_ctx);
3909 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
3910
cd3e32ce 3911 SCMutexLock(&f.m);
429c6388
AS
3912 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER | STREAM_START,
3913 request1, request1_len);
5311cd48
AS
3914 if (r != 0) {
3915 printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
cd3e32ce 3916 SCMutexUnlock(&f.m);
5311cd48
AS
3917 goto end;
3918 }
cd3e32ce 3919 SCMutexUnlock(&f.m);
5311cd48
AS
3920
3921 smtp_state = f.alstate;
3922 if (smtp_state == NULL) {
3923 printf("no smtp state: ");
3924 goto end;
3925 }
3926
3927 /* do detect */
3928 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3929
3930 if (PacketAlertCheck(p, 1)) {
3931 printf("sid 1 matched. It shouldn't match: ");
3932 goto end;
3933 }
3934
cd3e32ce 3935 SCMutexLock(&f.m);
429c6388
AS
3936 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT | STREAM_TOCLIENT,
3937 reply1, reply1_len);
5311cd48
AS
3938 if (r == 0) {
3939 printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
cd3e32ce 3940 SCMutexUnlock(&f.m);
5311cd48
AS
3941 goto end;
3942 }
cd3e32ce 3943 SCMutexUnlock(&f.m);
5311cd48
AS
3944
3945 /* do detect */
3946 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3947
3948 if (!PacketAlertCheck(p, 1)) {
3949 printf("sid 1 didn't match. Should have matched: ");
3950 goto end;
3951 }
3952
3953 result = 1;
3954
3955end:
3956 SigGroupCleanup(de_ctx);
3957 SigCleanSignatures(de_ctx);
3958
3959 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
3960 DetectEngineCtxFree(de_ctx);
3961
429c6388 3962 if (alp_tctx != NULL)
fdefb65b 3963 AppLayerParserThreadCtxFree(alp_tctx);
5311cd48 3964 StreamTcpFreeConfig(TRUE);
5311cd48
AS
3965 FLOW_DESTROY(&f);
3966 UTHFreePackets(&p, 1);
3967 return result;
3968}
3969
3970int SMTPParserTest13(void)
3971{
3972 int result = 0;
3973 Signature *s = NULL;
3974 ThreadVars th_v;
3975 Packet *p = NULL;
3976 Flow f;
3977 TcpSession ssn;
3978 DetectEngineThreadCtx *det_ctx = NULL;
3979 DetectEngineCtx *de_ctx = NULL;
3980 SMTPState *smtp_state = NULL;
3981 int r = 0;
3982
3983 /* EHLO boo.com<CR><LF> */
3984 uint8_t request1[] = {
3985 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3986 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3987 };
3988 int32_t request1_len = sizeof(request1);
3989
3990 /* 250<CR><LF>
3991 */
3992 uint8_t reply1[] = {
3993 0x32, 0x35, 0x30, 0x0d, 0x0a,
3994 };
3995 uint32_t reply1_len = sizeof(reply1);
3996
3997 /* MAIL FROM:pbsf@asdfs.com<CR><LF>
3998 * RCPT TO:pbsf@asdfs.com<CR><LF>
3999 * DATA<CR><LF>
4000 * STARTTLS<CR><LF>
4001 */
4002 uint8_t request2[] = {
4003 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
4004 0x4d, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
4005 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
4006 0x0d, 0x0a, 0x52, 0x43, 0x50, 0x54, 0x20, 0x54,
4007 0x4f, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
4008 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
4009 0x0d, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a,
4010 0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
4011 0x0d, 0x0a
4012 };
4013 uint32_t request2_len = sizeof(request2);
4014
8dbf7a0d 4015 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
429c6388 4016
5311cd48
AS
4017 memset(&th_v, 0, sizeof(th_v));
4018 memset(&f, 0, sizeof(f));
4019 memset(&ssn, 0, sizeof(ssn));
4020
4021 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
4022
4023 FLOW_INITIALIZE(&f);
4024 f.protoctx = (void *)&ssn;
429c6388 4025 f.proto = IPPROTO_TCP;
5311cd48
AS
4026 p->flow = &f;
4027 p->flowflags |= FLOW_PKT_TOSERVER;
4028 p->flowflags |= FLOW_PKT_ESTABLISHED;
4029 p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
4030 f.alproto = ALPROTO_SMTP;
4031
4032 StreamTcpInitConfig(TRUE);
5311cd48
AS
4033
4034 de_ctx = DetectEngineCtxInit();
4035 if (de_ctx == NULL)
4036 goto end;
4037
4038 de_ctx->flags |= DE_QUIET;
4039
4040 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
4041 "(msg:\"SMTP event handling\"; "
7fa22e84 4042 "app-layer-event: "
5311cd48
AS
4043 "smtp.invalid_pipelined_sequence; "
4044 "sid:1;)");
4045 if (s == NULL)
4046 goto end;
4047
4048 SigGroupBuild(de_ctx);
4049 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
4050
cd3e32ce 4051 SCMutexLock(&f.m);
429c6388
AS
4052 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER | STREAM_START,
4053 request1, request1_len);
5311cd48
AS
4054 if (r != 0) {
4055 printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
cd3e32ce 4056 SCMutexUnlock(&f.m);
5311cd48
AS
4057 goto end;
4058 }
cd3e32ce 4059 SCMutexUnlock(&f.m);
5311cd48
AS
4060
4061 smtp_state = f.alstate;
4062 if (smtp_state == NULL) {
4063 printf("no smtp state: ");
4064 goto end;
4065 }
4066
4067 /* do detect */
4068 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4069
4070 if (PacketAlertCheck(p, 1)) {
4071 printf("sid 1 matched. It shouldn't match: ");
4072 goto end;
4073 }
4074
cd3e32ce 4075 SCMutexLock(&f.m);
429c6388
AS
4076 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
4077 reply1, reply1_len);
5311cd48
AS
4078 if (r != 0) {
4079 printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
cd3e32ce 4080 SCMutexUnlock(&f.m);
5311cd48
AS
4081 goto end;
4082 }
cd3e32ce 4083 SCMutexUnlock(&f.m);
5311cd48
AS
4084
4085 /* do detect */
4086 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4087
4088 if (PacketAlertCheck(p, 1)) {
4089 printf("sid 1 matched. It shouldn't match: ");
4090 goto end;
4091 }
4092
cd3e32ce 4093 SCMutexLock(&f.m);
429c6388
AS
4094 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
4095 request2, request2_len);
5311cd48
AS
4096 if (r != 0) {
4097 printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
cd3e32ce 4098 SCMutexUnlock(&f.m);
5311cd48
AS
4099 goto end;
4100 }
cd3e32ce 4101 SCMutexUnlock(&f.m);
5311cd48
AS
4102
4103 /* do detect */
4104 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4105
4106 if (!PacketAlertCheck(p, 1)) {
4107 printf("sid 1 didn't match. Should have matched: ");
4108 goto end;
4109 }
4110
4111 result = 1;
4112
4113end:
4114 SigGroupCleanup(de_ctx);
4115 SigCleanSignatures(de_ctx);
4116
4117 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
4118 DetectEngineCtxFree(de_ctx);
4119
429c6388 4120 if (alp_tctx != NULL)
fdefb65b 4121 AppLayerParserThreadCtxFree(alp_tctx);
5311cd48 4122 StreamTcpFreeConfig(TRUE);
5311cd48
AS
4123 FLOW_DESTROY(&f);
4124 UTHFreePackets(&p, 1);
4125 return result;
4126}
4127
c2dc6867
DA
4128/**
4129 * \test Test DATA command w/MIME message.
4130 */
4131int SMTPParserTest14(void)
4132{
4133 int result = 0;
4134 Flow f;
4135 int r = 0;
4136
4137 /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
6467a5d5 4138 static uint8_t welcome_reply[] = {
c2dc6867
DA
4139 0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
4140 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
4141 0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
4142 0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
4143 0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
4144 0x0d, 0x0a
4145 };
6467a5d5 4146 static uint32_t welcome_reply_len = sizeof(welcome_reply);
c2dc6867
DA
4147
4148 /* EHLO boo.com<CR><LF> */
6467a5d5 4149 static uint8_t request1[] = {
c2dc6867
DA
4150 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
4151 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
4152 };
6467a5d5 4153 static uint32_t request1_len = sizeof(request1);
c2dc6867
DA
4154 /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
4155 * 250-SIZE 35882577<CR><LF>
4156 * 250-8BITMIME<CR><LF>
4157 * 250-STARTTLS<CR><LF>
4158 * 250 ENHANCEDSTATUSCODES<CR><LF>
4159 */
6467a5d5 4160 static uint8_t reply1[] = {
c2dc6867
DA
4161 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
4162 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
4163 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
4164 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
4165 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
4166 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
4167 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
4168 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
4169 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
4170 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
4171 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
4172 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
4173 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
4174 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
4175 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
4176 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
4177 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
4178 };
6467a5d5 4179 static uint32_t reply1_len = sizeof(reply1);
c2dc6867
DA
4180
4181 /* MAIL FROM:asdff@asdf.com<CR><LF> */
6467a5d5 4182 static uint8_t request2[] = {
c2dc6867
DA
4183 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
4184 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
4185 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
4186 0x0d, 0x0a
4187 };
6467a5d5 4188 static uint32_t request2_len = sizeof(request2);
c2dc6867 4189 /* 250 2.1.0 Ok<CR><LF> */
6467a5d5 4190 static uint8_t reply2[] = {
c2dc6867
DA
4191 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
4192 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
4193 };
6467a5d5 4194 static uint32_t reply2_len = sizeof(reply2);
c2dc6867
DA
4195
4196 /* RCPT TO:bimbs@gmail.com<CR><LF> */
6467a5d5 4197 static uint8_t request3[] = {
c2dc6867
DA
4198 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
4199 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
4200 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
4201 0x0a
4202 };
6467a5d5 4203 static uint32_t request3_len = sizeof(request3);
c2dc6867 4204 /* 250 2.1.5 Ok<CR><LF> */
6467a5d5 4205 static uint8_t reply3[] = {
c2dc6867
DA
4206 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
4207 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
4208 };
6467a5d5 4209 static uint32_t reply3_len = sizeof(reply3);
c2dc6867
DA
4210
4211 /* DATA<CR><LF> */
6467a5d5 4212 static uint8_t request4[] = {
c2dc6867
DA
4213 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
4214 };
6467a5d5 4215 static uint32_t request4_len = sizeof(request4);
c2dc6867 4216 /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
6467a5d5 4217 static uint8_t reply4[] = {
c2dc6867
DA
4218 0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
4219 0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
4220 0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
4221 0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
4222 0x4c, 0x46, 0x3e, 0x0d, 0x0a
4223 };
6467a5d5 4224 static uint32_t reply4_len = sizeof(reply4);
c2dc6867
DA
4225
4226 /* MIME_MSG */
6467a5d5
TD
4227 static uint64_t filesize = 133;
4228 static uint8_t request4_msg[] = {
c2dc6867
DA
4229 0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72,
4230 0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E,
4231 0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
4232 0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A,
4233 0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61,
4234 0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74,
4235 0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61,
4236 0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
4237 0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73,
4238 0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F,
4239 0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61,
4240 0x73, 0x65, 0x36, 0x34, 0x0D, 0x0A, 0x43, 0x6F,
4241 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x44, 0x69,
4242 0x73, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F,
4243 0x6E, 0x3A, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63,
4244 0x68, 0x6D, 0x65, 0x6E, 0x74, 0x3B, 0x20, 0x66,
4245 0x69, 0x6C, 0x65, 0x6E, 0x61, 0x6D, 0x65, 0x3D,
4246 0x22, 0x74, 0x65, 0x73, 0x74, 0x2E, 0x65, 0x78,
4247 0x65, 0x22, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x54,
4248 0x56, 0x6F, 0x41, 0x41, 0x46, 0x42, 0x46, 0x41,
4249 0x41, 0x42, 0x4D, 0x41, 0x51, 0x45, 0x41, 0x61,
4250 0x69, 0x70, 0x59, 0x77, 0x77, 0x41, 0x41, 0x41,
4251 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
4252 0x41, 0x41, 0x44, 0x41, 0x51, 0x73, 0x42, 0x43,
4253 0x41, 0x41, 0x42, 0x41, 0x41, 0x43, 0x41, 0x41,
4254 0x41, 0x41, 0x41, 0x41, 0x48, 0x6B, 0x41, 0x41,
4255 0x41, 0x41, 0x4D, 0x41, 0x41, 0x41, 0x41, 0x65,
4256 0x51, 0x41, 0x41, 0x41, 0x41, 0x77, 0x41, 0x41,
4257 0x41, 0x41, 0x41, 0x41, 0x45, 0x41, 0x41, 0x42,
4258 0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
4259 0x41, 0x42, 0x30, 0x41, 0x41, 0x41, 0x41, 0x49,
4260 0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
4261 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
4262 0x41, 0x45, 0x41, 0x41, 0x49, 0x67, 0x41, 0x41,
4263 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4264 0x67, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4265 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4266 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4267 0x41, 0x42, 0x63, 0x58, 0x44, 0x59, 0x32, 0x4C,
4268 0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C,
4269 0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F,
4270 0x41, 0x3D, 0x3D, 0x0D,0x0A };
6467a5d5 4271 static uint32_t request4_msg_len = sizeof(request4_msg);
c2dc6867
DA
4272
4273 /* DATA COMPLETED */
6467a5d5 4274 static uint8_t request4_end[] = {
c2dc6867
DA
4275 0x0d, 0x0a, 0x2e, 0x0d, 0x0a
4276 };
6467a5d5 4277 static uint32_t request4_end_len = sizeof(request4_end);
c2dc6867 4278 /* 250 2.0.0 Ok: queued as 6A1AF20BF2<CR><LF> */
6467a5d5 4279 static uint8_t reply4_end[] = {
c2dc6867
DA
4280 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
4281 0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
4282 0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
4283 0x36, 0x41, 0x31, 0x41, 0x46, 0x32, 0x30, 0x42,
4284 0x46, 0x32, 0x0d, 0x0a
4285 };
6467a5d5 4286 static uint32_t reply4_end_len = sizeof(reply4_end);
c2dc6867
DA
4287
4288 /* QUIT<CR><LF> */
6467a5d5 4289 static uint8_t request5[] = {
c2dc6867
DA
4290 0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
4291 };
6467a5d5 4292 static uint32_t request5_len = sizeof(request5);
c2dc6867 4293 /* 221 2.0.0 Bye<CR><LF> */
6467a5d5 4294 static uint8_t reply5[] = {
c2dc6867
DA
4295 0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
4296 0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
4297 };
6467a5d5 4298 static uint32_t reply5_len = sizeof(reply5);
c2dc6867
DA
4299
4300 TcpSession ssn;
260872cc 4301 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
c2dc6867
DA
4302
4303 memset(&f, 0, sizeof(f));
4304 memset(&ssn, 0, sizeof(ssn));
4305
4306 FLOW_INITIALIZE(&f);
4307 f.protoctx = (void *)&ssn;
260872cc 4308 f.proto = IPPROTO_TCP;
c2dc6867
DA
4309
4310 StreamTcpInitConfig(TRUE);
c2dc6867 4311
260872cc
EL
4312 SCMutexLock(&f.m);
4313 /* Welcome reply */
4314 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
4315 welcome_reply, welcome_reply_len);
c2dc6867
DA
4316 if (r != 0) {
4317 printf("smtp check returned %" PRId32 ", expected 0: ", r);
260872cc 4318 SCMutexUnlock(&f.m);
c2dc6867
DA
4319 goto end;
4320 }
260872cc 4321 SCMutexUnlock(&f.m);
c2dc6867
DA
4322 SMTPState *smtp_state = f.alstate;
4323 if (smtp_state == NULL) {
4324 printf("no smtp state: ");
4325 goto end;
4326 }
4327 if (smtp_state->input_len != 0 ||
260872cc 4328 smtp_state->cmds_cnt != 0 ||
c2dc6867 4329 smtp_state->cmds_idx != 0 ||
260872cc
EL
4330 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
4331 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4332 goto end;
4333 }
4334
260872cc
EL
4335 SCMutexLock(&f.m);
4336 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
4337 request1, request1_len);
c2dc6867
DA
4338 if (r != 0) {
4339 printf("smtp check returned %" PRId32 ", expected 0: ", r);
260872cc 4340 SCMutexUnlock(&f.m);
c2dc6867
DA
4341 goto end;
4342 }
260872cc 4343 SCMutexUnlock(&f.m);
c2dc6867
DA
4344 if (smtp_state->input_len != 0 ||
4345 smtp_state->cmds_cnt != 1 ||
4346 smtp_state->cmds_idx != 0 ||
4347 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4348 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
260872cc 4349 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4350 goto end;
4351 }
4352
260872cc 4353 SCMutexLock(&f.m);
c2dc6867 4354 /* EHLO Reply */
260872cc 4355 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
c2dc6867
DA
4356 reply1, reply1_len);
4357 if (r != 0) {
4358 printf("smtp check returned %" PRId32 ", expected 0: ", r);
260872cc 4359 SCMutexUnlock(&f.m);
c2dc6867
DA
4360 goto end;
4361 }
260872cc 4362 SCMutexUnlock(&f.m);
c2dc6867
DA
4363 if (smtp_state->input_len != 0 ||
4364 smtp_state->cmds_cnt != 0 ||
4365 smtp_state->cmds_idx != 0 ||
4366 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
260872cc 4367 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4368 goto end;
4369 }
4370
260872cc 4371 SCMutexLock(&f.m);
c2dc6867 4372 /* MAIL FROM Request */
260872cc 4373 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
c2dc6867
DA
4374 request2, request2_len);
4375 if (r != 0) {
4376 printf("smtp check returned %" PRId32 ", expected 0: ", r);
260872cc 4377 SCMutexUnlock(&f.m);
c2dc6867
DA
4378 goto end;
4379 }
260872cc 4380 SCMutexUnlock(&f.m);
c2dc6867
DA
4381 if (smtp_state->input_len != 0 ||
4382 smtp_state->cmds_cnt != 1 ||
4383 smtp_state->cmds_idx != 0 ||
4384 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4385 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
260872cc 4386 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4387 goto end;
4388 }
4389
260872cc 4390 SCMutexLock(&f.m);
c2dc6867 4391 /* MAIL FROM Reply */
260872cc 4392 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
c2dc6867
DA
4393 reply2, reply2_len);
4394 if (r != 0) {
4395 printf("smtp check returned %" PRId32 ", expected 0: ", r);
260872cc 4396 SCMutexUnlock(&f.m);
c2dc6867
DA
4397 goto end;
4398 }
260872cc 4399 SCMutexUnlock(&f.m);
c2dc6867
DA
4400 if (smtp_state->input_len != 0 ||
4401 smtp_state->cmds_cnt != 0 ||
4402 smtp_state->cmds_idx != 0 ||
4403 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
260872cc 4404 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4405 goto end;
4406 }
4407
260872cc 4408 SCMutexLock(&f.m);
c2dc6867 4409 /* RCPT TO Request */
260872cc 4410 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
c2dc6867
DA
4411 request3, request3_len);
4412 if (r != 0) {
4413 printf("smtp check returned %" PRId32 ", expected 0: ", r);
260872cc 4414 SCMutexUnlock(&f.m);
c2dc6867
DA
4415 goto end;
4416 }
260872cc 4417 SCMutexUnlock(&f.m);
c2dc6867
DA
4418 if (smtp_state->input_len != 0 ||
4419 smtp_state->cmds_cnt != 1 ||
4420 smtp_state->cmds_idx != 0 ||
4421 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4422 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
260872cc 4423 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4424 goto end;
4425 }
4426
260872cc 4427 SCMutexLock(&f.m);
c2dc6867 4428 /* RCPT TO Reply */
260872cc 4429 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
c2dc6867
DA
4430 reply3, reply3_len);
4431 if (r != 0) {
4432 printf("smtp check returned %" PRId32 ", expected 0: ", r);
260872cc 4433 SCMutexUnlock(&f.m);
c2dc6867
DA
4434 goto end;
4435 }
260872cc 4436 SCMutexUnlock(&f.m);
c2dc6867
DA
4437 if (smtp_state->input_len != 0 ||
4438 smtp_state->cmds_cnt != 0 ||
4439 smtp_state->cmds_idx != 0 ||
4440 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
260872cc 4441 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4442 goto end;
4443 }
4444
4445 /* Enable mime decoding */
4446 smtp_config.decode_mime = 1;
4447 smtp_config.mime_config.decode_base64 = 1;
4448 smtp_config.mime_config.decode_quoted_printable = 1;
4449 MimeDecSetConfig(&smtp_config.mime_config);
4450
260872cc 4451 SCMutexLock(&f.m);
c2dc6867 4452 /* DATA request */
260872cc 4453 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
c2dc6867
DA
4454 request4, request4_len);
4455 if (r != 0) {
4456 printf("smtp check returned %" PRId32 ", expected 0: ", r);
260872cc 4457 SCMutexUnlock(&f.m);
c2dc6867
DA
4458 goto end;
4459 }
260872cc 4460 SCMutexUnlock(&f.m);
c2dc6867
DA
4461
4462 if (smtp_state->input_len != 0 ||
4463 smtp_state->cmds_cnt != 1 ||
4464 smtp_state->cmds_idx != 0 ||
4465 smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
4466 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
260872cc 4467 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4468 goto end;
4469 }
4470
260872cc 4471 SCMutexLock(&f.m);
c2dc6867 4472 /* Data reply */
260872cc 4473 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
c2dc6867
DA
4474 reply4, reply4_len);
4475 if (r != 0) {
4476 printf("smtp check returned %" PRId32 ", expected 0: ", r);
260872cc 4477 SCMutexUnlock(&f.m);
c2dc6867
DA
4478 goto end;
4479 }
260872cc 4480 SCMutexUnlock(&f.m);
c2dc6867
DA
4481 if (smtp_state->input_len != 0 ||
4482 smtp_state->cmds_cnt != 0 ||
4483 smtp_state->cmds_idx != 0 ||
4484 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
4485 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
260872cc 4486 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4487 goto end;
4488 }
4489
260872cc 4490 SCMutexLock(&f.m);
c2dc6867 4491 /* DATA message */
260872cc 4492 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
c2dc6867
DA
4493 request4_msg, request4_msg_len);
4494 if (r != 0) {
4495 printf("smtp check returned %" PRId32 ", expected 0: ", r);
260872cc 4496 SCMutexUnlock(&f.m);
c2dc6867
DA
4497 goto end;
4498 }
260872cc 4499 SCMutexUnlock(&f.m);
c2dc6867
DA
4500
4501 if (smtp_state->input_len != 0 ||
4502 smtp_state->cmds_cnt != 0 ||
4503 smtp_state->cmds_idx != 0 ||
56b74c8b 4504 smtp_state->curr_tx->mime_state == NULL || smtp_state->curr_tx->msg_head == NULL || /* MIME data structures */
c2dc6867
DA
4505 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
4506 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
260872cc 4507 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4508 goto end;
4509 }
4510
260872cc 4511 SCMutexLock(&f.m);
c2dc6867 4512 /* DATA . request */
260872cc 4513 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
c2dc6867
DA
4514 request4_end, request4_end_len);
4515 if (r != 0) {
4516 printf("smtp check returned %" PRId32 ", expected 0: ", r);
260872cc 4517 SCMutexUnlock(&f.m);
c2dc6867
DA
4518 goto end;
4519 }
260872cc 4520 SCMutexUnlock(&f.m);
c2dc6867
DA
4521
4522 if (smtp_state->input_len != 0 ||
4523 smtp_state->cmds_cnt != 1 ||
4524 smtp_state->cmds_idx != 0 ||
4525 smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
56b74c8b 4526 smtp_state->curr_tx->mime_state == NULL || smtp_state->curr_tx->msg_head == NULL || /* MIME data structures */
c2dc6867 4527 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
260872cc 4528 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4529 goto end;
4530 }
4531
4532 SMTPState *state = (SMTPState *) f.alstate;
4533 FileContainer *files = state->files_ts;
4534 if (files != NULL && files->head != NULL) {
4535 File *file = files->head;
4536
4537 if(strncmp((const char *)file->name, "test.exe", 8) != 0){
4538 printf("smtp-mime file name is incorrect");
4539 goto end;
4540 }
4541 if(file->size != filesize){
5461294a 4542 printf("smtp-mime file size %"PRIu64" is incorrect", file->size);
c2dc6867
DA
4543 goto end;
4544 }
6467a5d5
TD
4545 static uint8_t org_binary[] = {
4546 0x4D, 0x5A, 0x00, 0x00, 0x50, 0x45, 0x00, 0x00,
c2dc6867
DA
4547 0x4C, 0x01, 0x01, 0x00, 0x6A, 0x2A, 0x58, 0xC3,
4548 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4549 0x04, 0x00, 0x03, 0x01, 0x0B, 0x01, 0x08, 0x00,
4550 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
4551 0x79, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
4552 0x79, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
4553 0x00, 0x00, 0x40, 0x00, 0x04, 0x00, 0x00, 0x00,
4554 0x04, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00,
4555 0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
4556 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00,
4557 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4558 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4559 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4560 0x00, 0x00, 0x00, 0x00, 0x5C, 0x5C, 0x36, 0x36,
4561 0x2E, 0x39, 0x33, 0x2E, 0x36, 0x38, 0x2E, 0x36,
4562 0x5C, 0x7A, 0x00, 0x00, 0x38,};
4563 uint64_t z;
6467a5d5 4564 for (z=0; z < filesize; z++){
c2dc6867
DA
4565 if(org_binary[z] != file->chunks_head->data[z]){
4566 printf("smtp-mime file data incorrect\n");
4567 goto end;
4568 }
4569 }
4570 }
4571
260872cc 4572 SCMutexLock(&f.m);
c2dc6867 4573 /* DATA . reply */
260872cc 4574 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
c2dc6867
DA
4575 reply4_end, reply4_end_len);
4576 if (r != 0) {
4577 printf("smtp check returned %" PRId32 ", expected 0: ", r);
260872cc 4578 SCMutexUnlock(&f.m);
c2dc6867
DA
4579 goto end;
4580 }
260872cc 4581 SCMutexUnlock(&f.m);
c2dc6867
DA
4582 if (smtp_state->input_len != 0 ||
4583 smtp_state->cmds_cnt != 0 ||
4584 smtp_state->cmds_idx != 0 ||
4585 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
260872cc 4586 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4587 goto end;
4588 }
4589
260872cc 4590 SCMutexLock(&f.m);
c2dc6867 4591 /* QUIT Request */
260872cc 4592 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
c2dc6867
DA
4593 request5, request5_len);
4594 if (r != 0) {
4595 printf("smtp check returned %" PRId32 ", expected 0: ", r);
260872cc 4596 SCMutexUnlock(&f.m);
c2dc6867
DA
4597 goto end;
4598 }
260872cc 4599 SCMutexUnlock(&f.m);
c2dc6867
DA
4600 if (smtp_state->input_len != 0 ||
4601 smtp_state->cmds_cnt != 1 ||
4602 smtp_state->cmds_idx != 0 ||
4603 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4604 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
260872cc 4605 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4606 goto end;
4607 }
4608
260872cc 4609 SCMutexLock(&f.m);
c2dc6867 4610 /* QUIT Reply */
260872cc 4611 r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
c2dc6867
DA
4612 reply5, reply5_len);
4613 if (r != 0) {
4614 printf("smtp check returned %" PRId32 ", expected 0: ", r);
260872cc 4615 SCMutexUnlock(&f.m);
c2dc6867
DA
4616 goto end;
4617 }
260872cc 4618 SCMutexUnlock(&f.m);
c2dc6867
DA
4619 if (smtp_state->input_len != 0 ||
4620 smtp_state->cmds_cnt != 0 ||
4621 smtp_state->cmds_idx != 0 ||
4622 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
260872cc 4623 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4624 goto end;
4625 }
4626
4627 result = 1;
260872cc
EL
4628end:
4629 if (alp_tctx != NULL)
4630 AppLayerParserThreadCtxFree(alp_tctx);
c2dc6867
DA
4631 StreamTcpFreeConfig(TRUE);
4632 FLOW_DESTROY(&f);
c2dc6867
DA
4633 return result;
4634}
4635
4636int SMTPProcessDataChunkTest01(void){
4637 Flow f;
4638 FLOW_INITIALIZE(&f);
4639 f.flags = FLOW_FILE_NO_STORE_TS;
4640 MimeDecParseState *state = MimeDecInitParser(&f, NULL);
4641 int ret;
d2657bec 4642 ret = SMTPProcessDataChunk(NULL, 0, state);
c2dc6867
DA
4643
4644 return ret;
4645}
4646
4647
4648int SMTPProcessDataChunkTest02(void){
4649 char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72,
4650 0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E,
4651 0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
4652 0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A,
4653 0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61,
4654 0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74,
4655 0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61,
4656 0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
4657 0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73,
4658 0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F,
4659 0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61,
4660 0x73, 0x65, 0x36, 0x34, 0x0D, 0x0A, 0x43, 0x6F,
4661 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x44, 0x69,
4662 0x73, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F,
4663 0x6E, 0x3A, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63,
4664 0x68, 0x6D, 0x65, 0x6E, 0x74, 0x3B, 0x20, 0x66,
4665 0x69, 0x6C, 0x65, 0x6E, 0x61, 0x6D, 0x65, 0x3D,
4666 0x22, 0x74, 0x65, 0x73, 0x74, 0x2E, 0x65, 0x78,
4667 0x65, 0x22, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x54,
4668 0x56, 0x6F, 0x41, 0x41, 0x46, 0x42, 0x46, 0x41,
4669 0x41, 0x42, 0x4D, 0x41, 0x51, 0x45, 0x41, 0x61,
4670 0x69, 0x70, 0x59, 0x77, 0x77, 0x41, 0x41, 0x41,
4671 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
4672 0x41, 0x41, 0x44, 0x41, 0x51, 0x73, 0x42, 0x43,
4673 0x41, 0x41, 0x42, 0x41, 0x41, 0x43, 0x41, 0x41,
4674 0x41, 0x41, 0x41, 0x41, 0x48, 0x6B, 0x41, 0x41,
4675 0x41, 0x41, 0x4D, 0x41, 0x41, 0x41, 0x41, 0x65,
4676 0x51, 0x41, 0x41, 0x41, 0x41, 0x77, 0x41, 0x41,
4677 0x41, 0x41, 0x41, 0x41, 0x45, 0x41, 0x41, 0x42,
4678 0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
4679 0x41, 0x42, 0x30, 0x41, 0x41, 0x41, 0x41, 0x49,
4680 0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
4681 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
4682 0x41, 0x45, 0x41, 0x41, 0x49, 0x67, 0x41, 0x41,
4683 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4684 0x67, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4685 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4686 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4687 0x41, 0x42, 0x63, 0x58, 0x44, 0x59, 0x32, 0x4C,
4688 0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C,
4689 0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F,
4690 0x41, 0x3D, 0x3D, 0x0D, 0x0A,};
4691
4692 Flow f;
4693 FLOW_INITIALIZE(&f);
4694 f.alstate = SMTPStateAlloc();
4695 MimeDecParseState *state = MimeDecInitParser(&f, NULL);
4696 ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT;
4697 state->body_begin = 1;
4698 int ret;
d2657bec 4699 ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state);
c2dc6867
DA
4700
4701
4702 return ret;
4703}
4704
4705
4706
4707int SMTPProcessDataChunkTest03(void){
4708 char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, };
4709 char mimemsg2[] = {0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, };
4710 char mimemsg3[] = {0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, };
4711 char mimemsg4[] = {0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A, };
4712 char mimemsg5[] = {0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, };
4713 char mimemsg6[] = {0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74, };
4714 char mimemsg7[] = {0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61, };
4715 char mimemsg8[] = {0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, };
4716 char mimemsg9[] = {0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73, };
4717 char mimemsg10[] = {0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F, };
4718 char mimemsg11[] = {0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61, };
4719 char mimemsg12[] = {0x73, 0x65, 0x36, 0x34, 0x0D, 0x0A, 0x43, 0x6F, };
4720
4721 Flow f;
4722 FLOW_INITIALIZE(&f);
4723 f.alstate = SMTPStateAlloc();
4724 MimeDecParseState *state = MimeDecInitParser(&f, NULL);
4725 ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT;
4726 int ret;
4727
4728 state->body_begin = 1;
d2657bec 4729 ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state);
c2dc6867
DA
4730 if(ret) goto end;
4731 state->body_begin = 0;
d2657bec 4732 ret = SMTPProcessDataChunk((uint8_t *)mimemsg2, sizeof(mimemsg2), state);
c2dc6867 4733 if(ret) goto end;
d2657bec 4734 ret = SMTPProcessDataChunk((uint8_t *)mimemsg3, sizeof(mimemsg3), state);
c2dc6867 4735 if(ret) goto end;
d2657bec 4736 ret = SMTPProcessDataChunk((uint8_t *)mimemsg4, sizeof(mimemsg4), state);
c2dc6867 4737 if(ret) goto end;
d2657bec 4738 ret = SMTPProcessDataChunk((uint8_t *)mimemsg5, sizeof(mimemsg5), state);
c2dc6867 4739 if(ret) goto end;
d2657bec 4740 ret = SMTPProcessDataChunk((uint8_t *)mimemsg6, sizeof(mimemsg6), state);
c2dc6867 4741 if(ret) goto end;
d2657bec 4742 ret = SMTPProcessDataChunk((uint8_t *)mimemsg7, sizeof(mimemsg7), state);
c2dc6867 4743 if(ret) goto end;
d2657bec 4744 ret = SMTPProcessDataChunk((uint8_t *)mimemsg8, sizeof(mimemsg8), state);
c2dc6867 4745 if(ret) goto end;
d2657bec 4746 ret = SMTPProcessDataChunk((uint8_t *)mimemsg9, sizeof(mimemsg9), state);
c2dc6867 4747 if(ret) goto end;
d2657bec 4748 ret = SMTPProcessDataChunk((uint8_t *)mimemsg10, sizeof(mimemsg10), state);
c2dc6867 4749 if(ret) goto end;
d2657bec 4750 ret = SMTPProcessDataChunk((uint8_t *)mimemsg11, sizeof(mimemsg11), state);
c2dc6867
DA
4751 if(ret) goto end;
4752 state->body_end = 1;
d2657bec 4753 ret = SMTPProcessDataChunk((uint8_t *)mimemsg12, sizeof(mimemsg12), state);
c2dc6867
DA
4754 if(ret) goto end;
4755
4756 end:
4757 return ret;
4758}
4759
4760
4761int SMTPProcessDataChunkTest04(void){
4762 char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, };
4763 char mimemsg2[] = {0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, };
4764 char mimemsg3[] = {0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, };
4765 char mimemsg4[] = {0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A, };
4766 char mimemsg5[] = {0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, };
4767 char mimemsg6[] = {0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74, };
4768 char mimemsg7[] = {0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61, };
4769 char mimemsg8[] = {0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, };
4770 char mimemsg9[] = {0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73, };
4771 char mimemsg10[] = {0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F, };
4772 char mimemsg11[] = {0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61, };
4773
4774 Flow f;
4775 FLOW_INITIALIZE(&f);
4776 f.alstate = SMTPStateAlloc();
4777 MimeDecParseState *state = MimeDecInitParser(&f, NULL);
4778 ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT;
4779 int ret = MIME_DEC_OK;
4780
4781 state->body_begin = 1;
d2657bec
GL
4782 if(SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state) != 0) goto end;
4783 if(SMTPProcessDataChunk((uint8_t *)mimemsg2, sizeof(mimemsg2), state) != 0) goto end;
4784 if(SMTPProcessDataChunk((uint8_t *)mimemsg3, sizeof(mimemsg3), state) != 0) goto end;
4785 if(SMTPProcessDataChunk((uint8_t *)mimemsg4, sizeof(mimemsg4), state) != 0) goto end;
4786 if(SMTPProcessDataChunk((uint8_t *)mimemsg5, sizeof(mimemsg5), state) != 0) goto end;
4787 if(SMTPProcessDataChunk((uint8_t *)mimemsg6, sizeof(mimemsg6), state) != 0) goto end;
4788 if(SMTPProcessDataChunk((uint8_t *)mimemsg7, sizeof(mimemsg7), state) != 0) goto end;
c2dc6867
DA
4789 state->body_begin = 0;
4790 state->body_end = 1;
d2657bec 4791 if(SMTPProcessDataChunk((uint8_t *)mimemsg8, sizeof(mimemsg8), state) != 0) goto end;
c2dc6867 4792 state->body_end = 0;
d2657bec
GL
4793 if(SMTPProcessDataChunk((uint8_t *)mimemsg9, sizeof(mimemsg9), state) != 0) goto end;
4794 if(SMTPProcessDataChunk((uint8_t *)mimemsg10, sizeof(mimemsg10), state) != 0) goto end;
4795 if(SMTPProcessDataChunk((uint8_t *)mimemsg11, sizeof(mimemsg11), state) != 0) goto end;
c2dc6867
DA
4796
4797 end:
4798 return ret;
4799}
4800
4801int SMTPProcessDataChunkTest05(void){
4802 char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72,
4803 0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E,
4804 0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
4805 0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A,
4806 0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C,
4807 0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F,
4808 0x41, 0x3D, 0x3D, 0x0D, 0x0A,};
4809
4810 Flow f;
4811 FLOW_INITIALIZE(&f);
4812 f.alstate = SMTPStateAlloc();
4813 MimeDecParseState *state = MimeDecInitParser(&f, NULL);
4814 ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT;
4815 state->body_begin = 1;
4816 int ret;
4817 uint64_t file_size = 0;
d2657bec 4818 ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state);
c2dc6867
DA
4819 state->body_begin = 0;
4820 if(ret){goto end;}
4821 SMTPState *smtp_state = (SMTPState *)((Flow *)state->data)->alstate;
4822 FileContainer *files = smtp_state->files_ts;
4823 File *file = files->head;
4824 file_size = file->size;
4825
4826 FileDisableStoring(&f, STREAM_TOSERVER);
4827 FileDisableMagic(&f, STREAM_TOSERVER);
4828 FileDisableMd5(&f, STREAM_TOSERVER);
d2657bec 4829 ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state);
c2dc6867
DA
4830 if(ret){goto end;}
4831 printf("%u\t%u\n", (uint32_t) file->size, (uint32_t) file_size);
4832 if(file->size == file_size){
4833 return 0;
4834 }else{
4835 return 1;
4836 }
4837
4838 end:
4839 return ret;
4840}
4841
87599bc7
AS
4842#endif /* UNITTESTS */
4843
576ec7da
AS
4844void SMTPParserRegisterTests(void)
4845{
87599bc7 4846#ifdef UNITTESTS
576ec7da
AS
4847 UtRegisterTest("SMTPParserTest01", SMTPParserTest01, 1);
4848 UtRegisterTest("SMTPParserTest02", SMTPParserTest02, 1);
4849 UtRegisterTest("SMTPParserTest03", SMTPParserTest03, 1);
4850 UtRegisterTest("SMTPParserTest04", SMTPParserTest04, 1);
4851 UtRegisterTest("SMTPParserTest05", SMTPParserTest05, 1);
d3ca65de 4852 UtRegisterTest("SMTPParserTest06", SMTPParserTest06, 1);
4a6908d3
AS
4853 UtRegisterTest("SMTPParserTest07", SMTPParserTest07, 1);
4854 UtRegisterTest("SMTPParserTest08", SMTPParserTest08, 1);
4855 UtRegisterTest("SMTPParserTest09", SMTPParserTest09, 1);
4856 UtRegisterTest("SMTPParserTest10", SMTPParserTest10, 1);
4857 UtRegisterTest("SMTPParserTest11", SMTPParserTest11, 1);
5311cd48
AS
4858 UtRegisterTest("SMTPParserTest12", SMTPParserTest12, 1);
4859 UtRegisterTest("SMTPParserTest13", SMTPParserTest13, 1);
c2dc6867
DA
4860 UtRegisterTest("SMTPParserTest14", SMTPParserTest14, 1);
4861 UtRegisterTest("SMTPProcessDataChunkTest01", SMTPProcessDataChunkTest01, 0);
4862 UtRegisterTest("SMTPProcessDataChunkTest02", SMTPProcessDataChunkTest02, 0);
4863 UtRegisterTest("SMTPProcessDataChunkTest03", SMTPProcessDataChunkTest03, 0);
4864 UtRegisterTest("SMTPProcessDataChunkTest04", SMTPProcessDataChunkTest04, 0);
4865 UtRegisterTest("SMTPProcessDataChunkTest05", SMTPProcessDataChunkTest05, 0);
87599bc7 4866#endif /* UNITTESTS */
4a6908d3 4867
576ec7da
AS
4868 return;
4869}