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