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