]> git.ipfire.org Git - people/ms/suricata.git/blame - src/app-layer-smtp.c
app-layer API optimizations and cleanups
[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
e6044aaf 160#define SMTP_MPM mpm_default_matcher
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
ab1200fb 331static void SMTPSetEvent(SMTPState *s, uint8_t e)
d209699a
VJ
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
569cc5d2 374 uint64_t file_size = FileDataSize(file);
e43ce0a9
VJ
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;
6f42ae91 957 AppLayerRequestProtocolTLSUpgrade(f);
e8800b18 958 state->curr_tx->done = 1;
576ec7da
AS
959 } else {
960 /* decoder event */
d209699a 961 SMTPSetEvent(state, SMTP_DECODER_EVENT_TLS_REJECTED);
576ec7da
AS
962 }
963 } else if (state->cmds[state->cmds_idx] == SMTP_COMMAND_DATA) {
4d38a571 964 if (reply_code == SMTP_REPLY_354) {
576ec7da
AS
965 /* Next comes the mail for the DATA command in toserver direction */
966 state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE;
967 } else {
968 /* decoder event */
d209699a 969 SMTPSetEvent(state, SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED);
576ec7da
AS
970 }
971 } else {
4d38a571
AS
972 /* we don't care for any other command for now */
973 /* check if reply falls in the valid list of replies for SMTP. If not
974 * decoder event */
576ec7da
AS
975 }
976
4d38a571 977 /* if it is a multi-line reply, we need to move the index only once for all
576ec7da
AS
978 * the line of the reply. We unset the multiline flag on the last
979 * line of the multiline reply, following which we increment the index */
980 if (!(state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY)) {
981 state->cmds_idx++;
982 }
983
984 /* if we have matched all the buffered commands, reset the cnt and index */
985 if (state->cmds_idx == state->cmds_cnt) {
986 state->cmds_cnt = 0;
987 state->cmds_idx = 0;
988 }
989
990 return 0;
991}
992
d3ca65de
AS
993static int SMTPParseCommandBDAT(SMTPState *state)
994{
7b0f261f
VJ
995 SCEnter();
996
d3ca65de
AS
997 int i = 4;
998 while (i < state->current_line_len) {
999 if (state->current_line[i] != ' ') {
1000 break;
1001 }
1002 i++;
1003 }
1004 if (i == 4) {
1005 /* decoder event */
1006 return -1;
1007 }
1008 if (i == state->current_line_len) {
1009 /* decoder event */
1010 return -1;
1011 }
25638832 1012 char *endptr = NULL;
d3ca65de
AS
1013 state->bdat_chunk_len = strtoul((const char *)state->current_line + i,
1014 (char **)&endptr, 10);
25638832 1015 if ((uint8_t *)endptr == state->current_line + i) {
d3ca65de
AS
1016 /* decoder event */
1017 return -1;
1018 }
1019
1020 return 0;
1021}
1022
7bca8268
EL
1023static int SMTPParseCommandWithParam(SMTPState *state, uint8_t prefix_len, uint8_t **target, uint16_t *target_len)
1024{
1025 int i = prefix_len + 1;
1026 int spc_i = 0;
1027
1028 while (i < state->current_line_len) {
1029 if (state->current_line[i] != ' ') {
1030 break;
1031 }
1032 i++;
1033 }
1034
1035 /* rfc1870: with the size extension the mail from can be followed by an option.
1036 We use the space separator to detect it. */
1037 spc_i = i;
1038 while (spc_i < state->current_line_len) {
1039 if (state->current_line[spc_i] == ' ') {
1040 break;
1041 }
1042 spc_i++;
1043 }
1044
7bca8268
EL
1045 *target = SCMalloc(spc_i - i + 1);
1046 if (*target == NULL)
1047 return -1;
1048 memcpy(*target, state->current_line + i, spc_i - i);
1049 (*target)[spc_i - i] = '\0';
1050 *target_len = spc_i - i;
1051
1052 return 0;
7bca8268
EL
1053}
1054
1055static int SMTPParseCommandHELO(SMTPState *state)
1056{
10e2e2a8
EL
1057 if (state->helo) {
1058 SMTPSetEvent(state, SMTP_DECODER_EVENT_DUPLICATE_FIELDS);
1059 return 0;
1060 }
7bca8268
EL
1061 return SMTPParseCommandWithParam(state, 4, &state->helo, &state->helo_len);
1062}
1063
1064static int SMTPParseCommandMAILFROM(SMTPState *state)
1065{
10e2e2a8
EL
1066 if (state->curr_tx->mail_from) {
1067 SMTPSetEvent(state, SMTP_DECODER_EVENT_DUPLICATE_FIELDS);
1068 return 0;
1069 }
7bca8268
EL
1070 return SMTPParseCommandWithParam(state, 9,
1071 &state->curr_tx->mail_from,
1072 &state->curr_tx->mail_from_len);
1073}
1074
752fdba9
EL
1075static int SMTPParseCommandRCPTTO(SMTPState *state)
1076{
1077 uint8_t *rcptto;
1078 uint16_t rcptto_len;
1079
1080 if (SMTPParseCommandWithParam(state, 7, &rcptto, &rcptto_len) == 0) {
1081 SMTPString *rcptto_str = SMTPStringAlloc();
1082 if (rcptto_str) {
1083 rcptto_str->str = rcptto;
1084 rcptto_str->len = rcptto_len;
1085 TAILQ_INSERT_TAIL(&state->curr_tx->rcpt_to_list, rcptto_str, next);
1086 } else {
1087 SCFree(rcptto);
1088 return -1;
1089 }
1090 } else {
1091 return -1;
1092 }
1093 return 0;
1094}
1095
7c3b22da
VJ
1096/* consider 'rset' and 'quit' to be part of the existing state */
1097static int NoNewTx(SMTPState *state)
1098{
1099 if (!(state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1100 if (state->current_line_len >= 4 &&
1101 SCMemcmpLowercase("rset", state->current_line, 4) == 0) {
1102 return 1;
1103 } else if (state->current_line_len >= 4 &&
1104 SCMemcmpLowercase("quit", state->current_line, 4) == 0) {
1105 return 1;
1106 }
1107 }
1108 return 0;
1109}
1110
576ec7da 1111static int SMTPProcessRequest(SMTPState *state, Flow *f,
9634e60e 1112 AppLayerParserState *pstate)
576ec7da 1113{
7b0f261f 1114 SCEnter();
d209699a
VJ
1115 SMTPTransaction *tx = state->curr_tx;
1116
7c3b22da 1117 if (state->curr_tx == NULL || (state->curr_tx->done && !NoNewTx(state))) {
d209699a
VJ
1118 tx = SMTPTransactionCreate();
1119 if (tx == NULL)
1120 return -1;
1121 state->curr_tx = tx;
1122 TAILQ_INSERT_TAIL(&state->tx_list, tx, next);
1123 tx->tx_id = state->tx_cnt++;
1124 }
7b0f261f 1125
0d7159b5 1126 if (!(state->parser_state & SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
d209699a 1127 SMTPSetEvent(state, SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE);
0d7159b5
AS
1128 }
1129
576ec7da
AS
1130 /* there are 2 commands that can push it into this COMMAND_DATA mode -
1131 * STARTTLS and DATA */
1132 if (!(state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
d3ca65de
AS
1133 int r = 0;
1134
576ec7da
AS
1135 if (state->current_line_len >= 8 &&
1136 SCMemcmpLowercase("starttls", state->current_line, 8) == 0) {
1137 state->current_command = SMTP_COMMAND_STARTTLS;
1138 } else if (state->current_line_len >= 4 &&
1139 SCMemcmpLowercase("data", state->current_line, 4) == 0) {
1140 state->current_command = SMTP_COMMAND_DATA;
c2dc6867 1141 if (smtp_config.decode_mime) {
5dbedbfa
EL
1142 if (tx->mime_state) {
1143 /* We have 2 chained mails and did not detect the end
1144 * of first one. So we start a new transaction. */
1145 tx->mime_state->state_flag = PARSE_ERROR;
1146 SMTPSetEvent(state, SMTP_DECODER_EVENT_UNPARSABLE_CONTENT);
1147 tx = SMTPTransactionCreate();
1148 if (tx == NULL)
1149 return -1;
1150 state->curr_tx = tx;
1151 TAILQ_INSERT_TAIL(&state->tx_list, tx, next);
1152 tx->tx_id = state->tx_cnt++;
1153 }
d2657bec 1154 tx->mime_state = MimeDecInitParser(f, SMTPProcessDataChunk);
56b74c8b 1155 if (tx->mime_state == NULL) {
c2dc6867
DA
1156 SCLogError(SC_ERR_MEM_ALLOC, "MimeDecInitParser() failed to "
1157 "allocate data");
1158 return MIME_DEC_ERR_MEM;
1159 }
1160
1161 /* Add new MIME message to end of list */
56b74c8b
VJ
1162 if (tx->msg_head == NULL) {
1163 tx->msg_head = tx->mime_state->msg;
1164 tx->msg_tail = tx->mime_state->msg;
c2dc6867
DA
1165 }
1166 else {
56b74c8b
VJ
1167 tx->msg_tail->next = tx->mime_state->msg;
1168 tx->msg_tail = tx->mime_state->msg;
c2dc6867
DA
1169 }
1170 }
1171
d3ca65de
AS
1172 } else if (state->current_line_len >= 4 &&
1173 SCMemcmpLowercase("bdat", state->current_line, 4) == 0) {
1174 r = SMTPParseCommandBDAT(state);
7b0f261f
VJ
1175 if (r == -1) {
1176 SCReturnInt(-1);
1177 }
d3ca65de
AS
1178 state->current_command = SMTP_COMMAND_BDAT;
1179 state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE;
7bca8268
EL
1180 } else if (state->current_line_len >= 4 &&
1181 ((SCMemcmpLowercase("helo", state->current_line, 4) == 0) ||
1182 SCMemcmpLowercase("ehlo", state->current_line, 4) == 0)) {
1183 r = SMTPParseCommandHELO(state);
1184 if (r == -1) {
1185 SCReturnInt(-1);
1186 }
1187 state->current_command = SMTP_COMMAND_OTHER_CMD;
1188 } else if (state->current_line_len >= 9 &&
1189 SCMemcmpLowercase("mail from", state->current_line, 9) == 0) {
1190 r = SMTPParseCommandMAILFROM(state);
1191 if (r == -1) {
1192 SCReturnInt(-1);
1193 }
1194 state->current_command = SMTP_COMMAND_OTHER_CMD;
752fdba9
EL
1195 } else if (state->current_line_len >= 7 &&
1196 SCMemcmpLowercase("rcpt to", state->current_line, 7) == 0) {
1197 r = SMTPParseCommandRCPTTO(state);
1198 if (r == -1) {
1199 SCReturnInt(-1);
1200 }
1201 state->current_command = SMTP_COMMAND_OTHER_CMD;
576ec7da
AS
1202 } else {
1203 state->current_command = SMTP_COMMAND_OTHER_CMD;
1204 }
1205
1206 /* Every command is inserted into a command buffer, to be matched
1207 * against reply(ies) sent by the server */
1208 if (SMTPInsertCommandIntoCommandBuffer(state->current_command,
5311cd48 1209 state, f) == -1) {
7b0f261f 1210 SCReturnInt(-1);
576ec7da 1211 }
d3ca65de 1212
7b0f261f 1213 SCReturnInt(r);
576ec7da
AS
1214 }
1215
1216 switch (state->current_command) {
1217 case SMTP_COMMAND_STARTTLS:
1218 return SMTPProcessCommandSTARTTLS(state, f, pstate);
1219
1220 case SMTP_COMMAND_DATA:
1221 return SMTPProcessCommandDATA(state, f, pstate);
1222
d3ca65de
AS
1223 case SMTP_COMMAND_BDAT:
1224 return SMTPProcessCommandBDAT(state, f, pstate);
1225
576ec7da
AS
1226 default:
1227 /* we have nothing to do with any other command at this instant.
1228 * Just let it go through */
7b0f261f 1229 SCReturnInt(0);
576ec7da
AS
1230 }
1231}
1232
88115902 1233static int SMTPParse(int direction, Flow *f, SMTPState *state,
9634e60e 1234 AppLayerParserState *pstate, uint8_t *input,
997eaf42 1235 uint32_t input_len,
eec66c7b 1236 SMTPThreadCtx *thread_data)
576ec7da 1237{
7b0f261f
VJ
1238 SCEnter();
1239
4e7cb7b8
VJ
1240 if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) {
1241 SCReturnInt(1);
f4f53924
VJ
1242 } else if (input == NULL || input_len == 0) {
1243 SCReturnInt(-1);
4e7cb7b8
VJ
1244 }
1245
576ec7da
AS
1246 state->input = input;
1247 state->input_len = input_len;
88115902 1248 state->direction = direction;
576ec7da 1249
87599bc7
AS
1250 /* toserver */
1251 if (direction == 0) {
1252 while (SMTPGetLine(state) >= 0) {
d3ca65de 1253 if (SMTPProcessRequest(state, f, pstate) == -1)
7b0f261f 1254 SCReturnInt(-1);
87599bc7 1255 }
88115902 1256
87599bc7
AS
1257 /* toclient */
1258 } else {
1259 while (SMTPGetLine(state) >= 0) {
eec66c7b 1260 if (SMTPProcessReply(state, f, pstate, thread_data) == -1)
7b0f261f 1261 SCReturnInt(-1);
88115902 1262 }
576ec7da
AS
1263 }
1264
7b0f261f 1265 SCReturnInt(0);
576ec7da
AS
1266}
1267
88115902 1268static int SMTPParseClientRecord(Flow *f, void *alstate,
9634e60e 1269 AppLayerParserState *pstate,
576ec7da 1270 uint8_t *input, uint32_t input_len,
429c6388 1271 void *local_data)
576ec7da 1272{
7b0f261f
VJ
1273 SCEnter();
1274
88115902 1275 /* first arg 0 is toserver */
429c6388 1276 return SMTPParse(0, f, alstate, pstate, input, input_len, local_data);
88115902 1277}
576ec7da 1278
88115902 1279static int SMTPParseServerRecord(Flow *f, void *alstate,
9634e60e 1280 AppLayerParserState *pstate,
88115902 1281 uint8_t *input, uint32_t input_len,
429c6388 1282 void *local_data)
88115902 1283{
7b0f261f
VJ
1284 SCEnter();
1285
88115902 1286 /* first arg 1 is toclient */
429c6388 1287 return SMTPParse(1, f, alstate, pstate, input, input_len, local_data);
576ec7da
AS
1288
1289 return 0;
1290}
1291
1292/**
1293 * \internal
1294 * \brief Function to allocate SMTP state memory.
1295 */
d2657bec 1296void *SMTPStateAlloc(void)
576ec7da
AS
1297{
1298 SMTPState *smtp_state = SCMalloc(sizeof(SMTPState));
e176be6f 1299 if (unlikely(smtp_state == NULL))
576ec7da
AS
1300 return NULL;
1301 memset(smtp_state, 0, sizeof(SMTPState));
1302
1303 smtp_state->cmds = SCMalloc(sizeof(uint8_t) *
1304 SMTP_COMMAND_BUFFER_STEPS);
1305 if (smtp_state->cmds == NULL) {
1306 SCFree(smtp_state);
1307 return NULL;
1308 }
1309 smtp_state->cmds_buffer_len = SMTP_COMMAND_BUFFER_STEPS;
1310
56b74c8b
VJ
1311 TAILQ_INIT(&smtp_state->tx_list);
1312
997eaf42
AS
1313 return smtp_state;
1314}
1315
752fdba9
EL
1316static SMTPString *SMTPStringAlloc(void)
1317{
1318 SMTPString *smtp_string = SCMalloc(sizeof(SMTPString));
1319 if (unlikely(smtp_string == NULL))
1320 return NULL;
1321 memset(smtp_string, 0, sizeof(SMTPString));
1322
1323 return smtp_string;
1324}
1325
1326
1327static void SMTPStringFree(SMTPString *str)
1328{
1329 if (str->str) {
1330 SCFree(str->str);
1331 }
1332 SCFree(str);
1333}
1334
997eaf42
AS
1335static void *SMTPLocalStorageAlloc(void)
1336{
1337 /* needed by the mpm */
eec66c7b
VJ
1338 SMTPThreadCtx *td = SCCalloc(1, sizeof(*td));
1339 if (td == NULL) {
1340 exit(EXIT_FAILURE);
1341 }
1342
1343 td->pmq = SCCalloc(1, sizeof(*td->pmq));
1344 if (td->pmq == NULL) {
4d38a571
AS
1345 exit(EXIT_FAILURE);
1346 }
eec66c7b 1347 PmqSetup(td->pmq);
4d38a571 1348
eec66c7b
VJ
1349 td->smtp_mpm_thread_ctx = SCCalloc(1, sizeof(MpmThreadCtx));
1350 if (unlikely(td->smtp_mpm_thread_ctx == NULL)) {
1351 exit(EXIT_FAILURE);
1352 }
1353 MpmInitThreadCtx(td->smtp_mpm_thread_ctx, SMTP_MPM);
1354 return td;
997eaf42
AS
1355}
1356
eec66c7b 1357static void SMTPLocalStorageFree(void *ptr)
997eaf42 1358{
eec66c7b
VJ
1359 SMTPThreadCtx *td = ptr;
1360 if (td != NULL) {
1361 if (td->pmq != NULL) {
1362 PmqFree(td->pmq);
1363 SCFree(td->pmq);
1364 }
1365
1366 if (td->smtp_mpm_thread_ctx != NULL) {
1367 mpm_table[SMTP_MPM].DestroyThreadCtx(smtp_mpm_ctx, td->smtp_mpm_thread_ctx);
1368 SCFree(td->smtp_mpm_thread_ctx);
1369 }
1370
1371 SCFree(td);
997eaf42
AS
1372 }
1373
1374 return;
576ec7da
AS
1375}
1376
56b74c8b
VJ
1377static void SMTPTransactionFree(SMTPTransaction *tx, SMTPState *state)
1378{
1379 if (tx->mime_state != NULL) {
1380 MimeDecDeInitParser(tx->mime_state);
1381 }
d209699a
VJ
1382 /* Free list of MIME message recursively */
1383 MimeDecFreeEntity(tx->msg_head);
1384
7b818494 1385 if (tx->decoder_events != NULL)
d209699a 1386 AppLayerDecoderEventsFreeEvents(&tx->decoder_events);
7b818494 1387
e984a572
VJ
1388 if (tx->de_state != NULL)
1389 DetectEngineStateFree(tx->de_state);
7bca8268
EL
1390
1391 if (tx->mail_from)
1392 SCFree(tx->mail_from);
1393
752fdba9
EL
1394 SMTPString *str = NULL;
1395 while ((str = TAILQ_FIRST(&tx->rcpt_to_list))) {
1396 TAILQ_REMOVE(&tx->rcpt_to_list, str, next);
1397 SMTPStringFree(str);
1398 }
d209699a
VJ
1399#if 0
1400 if (tx->decoder_events->cnt <= smtp_state->events)
1401 smtp_state->events -= tx->decoder_events->cnt;
1402 else
1403 smtp_state->events = 0;
1404#endif
56b74c8b
VJ
1405 SCFree(tx);
1406}
1407
576ec7da
AS
1408/**
1409 * \internal
1410 * \brief Function to free SMTP state memory.
1411 */
1412static void SMTPStateFree(void *p)
1413{
1414 SMTPState *smtp_state = (SMTPState *)p;
1415
1416 if (smtp_state->cmds != NULL) {
1417 SCFree(smtp_state->cmds);
1418 }
88115902
AS
1419 if (smtp_state->ts_current_line_db) {
1420 SCFree(smtp_state->ts_db);
1421 }
1422 if (smtp_state->tc_current_line_db) {
1423 SCFree(smtp_state->tc_db);
1424 }
576ec7da 1425
7bca8268
EL
1426 if (smtp_state->helo) {
1427 SCFree(smtp_state->helo);
1428 }
1429
c2dc6867 1430 FileContainerFree(smtp_state->files_ts);
56b74c8b
VJ
1431
1432 SMTPTransaction *tx = NULL;
1433 while ((tx = TAILQ_FIRST(&smtp_state->tx_list))) {
56b74c8b
VJ
1434 TAILQ_REMOVE(&smtp_state->tx_list, tx, next);
1435 SMTPTransactionFree(tx, smtp_state);
1436 }
c2dc6867 1437
576ec7da
AS
1438 SCFree(smtp_state);
1439
1440 return;
1441}
1442
4d38a571
AS
1443static void SMTPSetMpmState(void)
1444{
1445 smtp_mpm_ctx = SCMalloc(sizeof(MpmCtx));
e176be6f 1446 if (unlikely(smtp_mpm_ctx == NULL)) {
4d38a571
AS
1447 exit(EXIT_FAILURE);
1448 }
1449 memset(smtp_mpm_ctx, 0, sizeof(MpmCtx));
a49cbf8a 1450 MpmInitCtx(smtp_mpm_ctx, SMTP_MPM);
4d38a571 1451
4d38a571
AS
1452 uint32_t i = 0;
1453 for (i = 0; i < sizeof(smtp_reply_map)/sizeof(SCEnumCharMap) - 1; i++) {
1454 SCEnumCharMap *map = &smtp_reply_map[i];
a49cbf8a
AS
1455 /* The third argument is 3, because reply code is always 3 bytes. */
1456 MpmAddPatternCI(smtp_mpm_ctx, (uint8_t *)map->enum_name, 3,
1457 0 /* defunct */, 0 /* defunct */,
cd8283bb 1458 i /* pattern id */, i /* rule id */ , 0 /* no flags */);
4d38a571
AS
1459 }
1460
1461 mpm_table[SMTP_MPM].Prepare(smtp_mpm_ctx);
68ddcdcc 1462
4d38a571
AS
1463}
1464
7a0dbc6f
JV
1465static void SMTPFreeMpmState(void)
1466{
7a0dbc6f
JV
1467 if (smtp_mpm_ctx != NULL) {
1468 mpm_table[SMTP_MPM].DestroyCtx(smtp_mpm_ctx);
eec66c7b 1469 SCFree(smtp_mpm_ctx);
7a0dbc6f
JV
1470 smtp_mpm_ctx = NULL;
1471 }
1472}
1473
ab1200fb 1474static int SMTPStateGetEventInfo(const char *event_name,
5e2d9dbd
AS
1475 int *event_id, AppLayerEventType *event_type)
1476{
1477 *event_id = SCMapEnumNameToValue(event_name, smtp_decoder_event_table);
1478 if (*event_id == -1) {
1479 SCLogError(SC_ERR_INVALID_ENUM_MAP, "event \"%s\" not present in "
1480 "smtp's enum map table.", event_name);
1481 /* yes this is fatal */
1482 return -1;
1483 }
1484
d209699a 1485 *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
5e2d9dbd
AS
1486
1487 return 0;
1488}
1489
429c6388
AS
1490static int SMTPRegisterPatternsForProtocolDetection(void)
1491{
9f6b5874 1492 if (AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_SMTP,
429c6388
AS
1493 "EHLO", 4, 0, STREAM_TOSERVER) < 0)
1494 {
1495 return -1;
1496 }
9f6b5874 1497 if (AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_SMTP,
429c6388
AS
1498 "HELO", 4, 0, STREAM_TOSERVER) < 0)
1499 {
1500 return -1;
1501 }
9f6b5874 1502 if (AppLayerProtoDetectPMRegisterPatternCI(IPPROTO_TCP, ALPROTO_SMTP,
429c6388
AS
1503 "QUIT", 4, 0, STREAM_TOSERVER) < 0)
1504 {
1505 return -1;
1506 }
1507
1508 return 0;
1509}
1510
56b74c8b
VJ
1511static void SMTPStateTransactionFree (void *state, uint64_t tx_id)
1512{
56b74c8b
VJ
1513 SMTPState *smtp_state = state;
1514 SMTPTransaction *tx = NULL;
1515 TAILQ_FOREACH(tx, &smtp_state->tx_list, next) {
1516 if (tx_id < tx->tx_id)
1517 break;
1518 else if (tx_id > tx->tx_id)
1519 continue;
1520
1521 if (tx == smtp_state->curr_tx)
1522 smtp_state->curr_tx = NULL;
56b74c8b
VJ
1523 TAILQ_REMOVE(&smtp_state->tx_list, tx, next);
1524 SMTPTransactionFree(tx, state);
1525 break;
1526 }
1527
1528
1529}
1530
f32d79df 1531/** \retval cnt highest tx id */
56b74c8b
VJ
1532static uint64_t SMTPStateGetTxCnt(void *state)
1533{
1534 uint64_t cnt = 0;
1535 SMTPState *smtp_state = state;
1536 if (smtp_state) {
f32d79df 1537 cnt = smtp_state->tx_cnt;
56b74c8b
VJ
1538 }
1539 SCLogDebug("returning %"PRIu64, cnt);
1540 return cnt;
1541}
1542
1543static void *SMTPStateGetTx(void *state, uint64_t id)
1544{
1545 SMTPState *smtp_state = state;
1546 if (smtp_state) {
1547 SMTPTransaction *tx = NULL;
1548
1549 if (smtp_state->curr_tx == NULL)
1550 return NULL;
1551 if (smtp_state->curr_tx->tx_id == id)
1552 return smtp_state->curr_tx;
1553
1554 TAILQ_FOREACH(tx, &smtp_state->tx_list, next) {
1555 if (tx->tx_id == id)
1556 return tx;
1557 }
1558 }
56b74c8b
VJ
1559 return NULL;
1560
1561}
1562
d484812d
MK
1563static void SMTPStateSetTxLogged(void *state, void *vtx, uint32_t logger)
1564{
1565 SMTPTransaction *tx = vtx;
1566 tx->logged |= logger;
1567}
1568
1569static int SMTPStateGetTxLogged(void *state, void *vtx, uint32_t logger)
1570{
1571 SMTPTransaction *tx = vtx;
1572 if (tx->logged & logger)
1573 return 1;
1574
1575 return 0;
1576}
1577
56b74c8b 1578static int SMTPStateGetAlstateProgressCompletionStatus(uint8_t direction) {
d209699a 1579 return 1;
56b74c8b
VJ
1580}
1581
1582static int SMTPStateGetAlstateProgress(void *vtx, uint8_t direction)
1583{
1584 SMTPTransaction *tx = vtx;
d209699a 1585 return tx->done;
56b74c8b
VJ
1586}
1587
1588static FileContainer *SMTPStateGetFiles(void *state, uint8_t direction)
1589{
1590 if (state == NULL)
1591 return NULL;
1592
1593 SMTPState *smtp_state = (SMTPState *)state;
1594
1595 if (direction & STREAM_TOCLIENT) {
1596 SCReturnPtr(NULL, "FileContainer");
1597 } else {
1598 SCLogDebug("smtp_state->files_ts %p", smtp_state->files_ts);
1599 SCReturnPtr(smtp_state->files_ts, "FileContainer");
1600 }
1601}
1602
08b06bac
VJ
1603static void SMTPStateTruncate(void *state, uint8_t direction)
1604{
1605 FileContainer *fc = SMTPStateGetFiles(state, direction);
1606 if (fc != NULL) {
1607 SCLogDebug("truncating stream, closing files in %s direction (container %p)",
1608 direction & STREAM_TOCLIENT ? "STREAM_TOCLIENT" : "STREAM_TOSERVER", fc);
1609 FileTruncateAllOpenFiles(fc);
1610 }
1611}
1612
d209699a
VJ
1613static AppLayerDecoderEvents *SMTPGetEvents(void *state, uint64_t tx_id)
1614{
1615 SCLogDebug("get SMTP events for TX %"PRIu64, tx_id);
1616
1617 SMTPTransaction *tx = SMTPStateGetTx(state, tx_id);
1618 if (tx != NULL) {
1619 return tx->decoder_events;
1620 }
1621 return NULL;
1622}
1623
e984a572
VJ
1624static DetectEngineState *SMTPGetTxDetectState(void *vtx)
1625{
1626 SMTPTransaction *tx = (SMTPTransaction *)vtx;
1627 return tx->de_state;
1628}
1629
f536099a 1630static int SMTPSetTxDetectState(void *state, void *vtx, DetectEngineState *s)
e984a572
VJ
1631{
1632 SMTPTransaction *tx = (SMTPTransaction *)vtx;
1633 tx->de_state = s;
1634 return 0;
1635}
1636
576ec7da 1637/**
e5c36952 1638 * \brief Register the SMTP Protocol parser.
576ec7da
AS
1639 */
1640void RegisterSMTPParsers(void)
1641{
ab1200fb 1642 const char *proto_name = "smtp";
10966245 1643
429c6388
AS
1644 if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
1645 AppLayerProtoDetectRegisterProtocol(ALPROTO_SMTP, proto_name);
1646 if (SMTPRegisterPatternsForProtocolDetection() < 0 )
1647 return;
ddde572f
AS
1648 } else {
1649 SCLogInfo("Protocol detection and parser disabled for %s protocol.",
1650 proto_name);
1651 return;
1652 }
576ec7da 1653
429c6388
AS
1654 if (AppLayerParserConfParserEnabled("tcp", proto_name)) {
1655 AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateAlloc, SMTPStateFree);
576ec7da 1656
429c6388
AS
1657 AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_SMTP, STREAM_TOSERVER,
1658 SMTPParseClientRecord);
1659 AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_SMTP, STREAM_TOCLIENT,
1660 SMTPParseServerRecord);
6cb00142 1661
429c6388 1662 AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetEventInfo);
d209699a 1663 AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetEvents);
f536099a 1664 AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_SMTP, NULL,
e984a572 1665 SMTPGetTxDetectState, SMTPSetTxDetectState);
576ec7da 1666
429c6388
AS
1667 AppLayerParserRegisterLocalStorageFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPLocalStorageAlloc,
1668 SMTPLocalStorageFree);
56b74c8b
VJ
1669
1670 AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateTransactionFree);
1671 AppLayerParserRegisterGetFilesFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetFiles);
1672 AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetAlstateProgress);
1673 AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTxCnt);
1674 AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTx);
d484812d
MK
1675 AppLayerParserRegisterLoggerFuncs(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTxLogged,
1676 SMTPStateSetTxLogged);
c4b918b6 1677 AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_SMTP,
56b74c8b 1678 SMTPStateGetAlstateProgressCompletionStatus);
08b06bac 1679 AppLayerParserRegisterTruncateFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateTruncate);
ddde572f
AS
1680 } else {
1681 SCLogInfo("Parsed disabled for %s protocol. Protocol detection"
1682 "still on.", proto_name);
1683 }
997eaf42 1684
4d38a571
AS
1685 SMTPSetMpmState();
1686
c2dc6867
DA
1687 SMTPConfigure();
1688
9faa4b74 1689#ifdef UNITTESTS
429c6388 1690 AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_SMTP, SMTPParserRegisterTests);
9faa4b74 1691#endif
576ec7da
AS
1692 return;
1693}
1694
7a0dbc6f
JV
1695/**
1696 * \brief Free memory allocated for global SMTP parser state.
1697 */
1698void SMTPParserCleanup(void)
1699{
1700 SMTPFreeMpmState();
1701}
1702
576ec7da
AS
1703/***************************************Unittests******************************/
1704
87599bc7
AS
1705#ifdef UNITTESTS
1706
e43ce0a9
VJ
1707static void SMTPTestInitConfig(void)
1708{
1709 MimeDecSetConfig(&smtp_config.mime_config);
1710
1711 smtp_config.content_limit = FILEDATA_CONTENT_LIMIT;
1712 smtp_config.content_inspect_window = FILEDATA_CONTENT_INSPECT_WINDOW;
1713 smtp_config.content_inspect_min_size = FILEDATA_CONTENT_INSPECT_MIN_SIZE;
1714
1715 smtp_config.sbcfg.buf_size = FILEDATA_CONTENT_INSPECT_WINDOW;
1716}
1717
576ec7da
AS
1718/*
1719 * \test Test STARTTLS.
1720 */
e43ce0a9 1721static int SMTPParserTest01(void)
576ec7da
AS
1722{
1723 int result = 0;
1724 Flow f;
1725 int r = 0;
1726
1727 /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
1728 uint8_t welcome_reply[] = {
1729 0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
1730 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
1731 0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
1732 0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
1733 0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
1734 0x0d, 0x0a
1735 };
1736 uint32_t welcome_reply_len = sizeof(welcome_reply);
1737
1738 /* EHLO [192.168.0.158]<CR><LF> */
1739 uint8_t request1[] = {
1740 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x5b, 0x31, 0x39,
1741 0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e,
1742 0x31, 0x35, 0x38, 0x5d, 0x0d, 0x0a
1743 };
1744 uint32_t request1_len = sizeof(request1);
1745 /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
1746 * 250-SIZE 35882577<CR><LF>
1747 * 250-8BITMIME<CR><LF>
1748 * 250-STARTTLS<CR><LF>
1749 * 250 ENHANCEDSTATUSCODES<CR><LF>
1750 */
1751 uint8_t reply1[] = {
1752 0x32, 0x35, 0x30, 0x2d, 0x6d, 0x78, 0x2e, 0x67,
1753 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
1754 0x6d, 0x20, 0x61, 0x74, 0x20, 0x79, 0x6f, 0x75,
1755 0x72, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
1756 0x65, 0x2c, 0x20, 0x5b, 0x31, 0x31, 0x37, 0x2e,
1757 0x31, 0x39, 0x38, 0x2e, 0x31, 0x31, 0x35, 0x2e,
1758 0x35, 0x30, 0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30,
1759 0x2d, 0x53, 0x49, 0x5a, 0x45, 0x20, 0x33, 0x35,
1760 0x38, 0x38, 0x32, 0x35, 0x37, 0x37, 0x0d, 0x0a,
1761 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49, 0x54,
1762 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35,
1763 0x30, 0x2d, 0x53, 0x54, 0x41, 0x52, 0x54, 0x54,
1764 0x4c, 0x53, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20,
1765 0x45, 0x4e, 0x48, 0x41, 0x4e, 0x43, 0x45, 0x44,
1766 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x43, 0x4f,
1767 0x44, 0x45, 0x53, 0x0d, 0x0a
1768 };
1769 uint32_t reply1_len = sizeof(reply1);
1770
1771 /* STARTTLS<CR><LF> */
1772 uint8_t request2[] = {
1773 0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
1774 0x0d, 0x0a
1775 };
1776 uint32_t request2_len = sizeof(request2);
1777 /* 220 2.0.0 Ready to start TLS<CR><LF> */
1778 uint8_t reply2[] = {
1779 0x32, 0x32, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
1780 0x30, 0x20, 0x52, 0x65, 0x61, 0x64, 0x79, 0x20,
1781 0x74, 0x6f, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74,
1782 0x20, 0x54, 0x4c, 0x53, 0x0d, 0x0a
1783 };
1784 uint32_t reply2_len = sizeof(reply2);
1785
1786 TcpSession ssn;
8dbf7a0d 1787 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
576ec7da
AS
1788
1789 memset(&f, 0, sizeof(f));
1790 memset(&ssn, 0, sizeof(ssn));
1791
1792 FLOW_INITIALIZE(&f);
1793 f.protoctx = (void *)&ssn;
429c6388 1794 f.proto = IPPROTO_TCP;
576ec7da
AS
1795
1796 StreamTcpInitConfig(TRUE);
e43ce0a9 1797 SMTPTestInitConfig();
576ec7da 1798
6530c3d0 1799 FLOWLOCK_WRLOCK(&f);
675fa564
GL
1800 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
1801 STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
576ec7da
AS
1802 if (r != 0) {
1803 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 1804 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
1805 goto end;
1806 }
6530c3d0 1807 FLOWLOCK_UNLOCK(&f);
06904c90 1808 SMTPState *smtp_state = f.alstate;
576ec7da
AS
1809 if (smtp_state == NULL) {
1810 printf("no smtp state: ");
1811 goto end;
1812 }
1813 if (smtp_state->input_len != 0 ||
0d7159b5 1814 smtp_state->cmds_cnt != 0 ||
576ec7da 1815 smtp_state->cmds_idx != 0 ||
0d7159b5 1816 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
576ec7da
AS
1817 printf("smtp parser in inconsistent state\n");
1818 goto end;
1819 }
1820
6530c3d0 1821 FLOWLOCK_WRLOCK(&f);
675fa564
GL
1822 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
1823 STREAM_TOSERVER, request1, request1_len);
576ec7da
AS
1824 if (r != 0) {
1825 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 1826 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
1827 goto end;
1828 }
6530c3d0 1829 FLOWLOCK_UNLOCK(&f);
576ec7da 1830 if (smtp_state->input_len != 0 ||
576ec7da
AS
1831 smtp_state->cmds_cnt != 1 ||
1832 smtp_state->cmds_idx != 0 ||
1833 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1834 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1835 printf("smtp parser in inconsistent state\n");
1836 goto end;
1837 }
1838
6530c3d0 1839 FLOWLOCK_WRLOCK(&f);
675fa564
GL
1840 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
1841 STREAM_TOCLIENT, reply1, reply1_len);
576ec7da
AS
1842 if (r != 0) {
1843 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 1844 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
1845 goto end;
1846 }
6530c3d0 1847 FLOWLOCK_UNLOCK(&f);
576ec7da 1848 if (smtp_state->input_len != 0 ||
576ec7da
AS
1849 smtp_state->cmds_cnt != 0 ||
1850 smtp_state->cmds_idx != 0 ||
1851 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1852 printf("smtp parser in inconsistent state\n");
1853 goto end;
1854 }
1855
6530c3d0 1856 FLOWLOCK_WRLOCK(&f);
675fa564
GL
1857 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
1858 STREAM_TOSERVER, request2, request2_len);
576ec7da
AS
1859 if (r != 0) {
1860 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 1861 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
1862 goto end;
1863 }
6530c3d0 1864 FLOWLOCK_UNLOCK(&f);
576ec7da 1865 if (smtp_state->input_len != 0 ||
576ec7da
AS
1866 smtp_state->cmds_cnt != 1 ||
1867 smtp_state->cmds_idx != 0 ||
1868 smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS ||
1869 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1870 printf("smtp parser in inconsistent state\n");
1871 goto end;
1872 }
1873
6530c3d0 1874 FLOWLOCK_WRLOCK(&f);
675fa564
GL
1875 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
1876 STREAM_TOCLIENT, reply2, reply2_len);
576ec7da
AS
1877 if (r != 0) {
1878 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 1879 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
1880 goto end;
1881 }
6530c3d0 1882 FLOWLOCK_UNLOCK(&f);
576ec7da 1883 if (smtp_state->input_len != 0 ||
576ec7da
AS
1884 smtp_state->cmds_cnt != 0 ||
1885 smtp_state->cmds_idx != 0 ||
1886 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
1887 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1888 printf("smtp parser in inconsistent state\n");
1889 goto end;
1890 }
1891
e8800b18 1892 if (!FlowChangeProto(&f)) {
576ec7da
AS
1893 goto end;
1894 }
1895
1896 result = 1;
1897end:
429c6388 1898 if (alp_tctx != NULL)
fdefb65b 1899 AppLayerParserThreadCtxFree(alp_tctx);
576ec7da
AS
1900 StreamTcpFreeConfig(TRUE);
1901 FLOW_DESTROY(&f);
1902 return result;
1903}
1904
1905/**
1906 * \test Test multiple DATA commands(full mail transactions).
1907 */
e43ce0a9 1908static int SMTPParserTest02(void)
576ec7da
AS
1909{
1910 int result = 0;
1911 Flow f;
1912 int r = 0;
1913
1914 /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
1915 uint8_t welcome_reply[] = {
1916 0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
1917 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
1918 0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
1919 0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
1920 0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
1921 0x0d, 0x0a
1922 };
1923 uint32_t welcome_reply_len = sizeof(welcome_reply);
1924
1925 /* EHLO boo.com<CR><LF> */
1926 uint8_t request1[] = {
1927 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
1928 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
1929 };
1930 uint32_t request1_len = sizeof(request1);
1931 /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
1932 * 250-SIZE 35882577<CR><LF>
1933 * 250-8BITMIME<CR><LF>
1934 * 250-STARTTLS<CR><LF>
1935 * 250 ENHANCEDSTATUSCODES<CR><LF>
1936 */
1937 uint8_t reply1[] = {
1938 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
1939 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
1940 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
1941 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
1942 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
1943 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
1944 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
1945 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
1946 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
1947 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
1948 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
1949 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
1950 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
1951 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
1952 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
1953 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
1954 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
1955 };
1956 uint32_t reply1_len = sizeof(reply1);
1957
1958 /* MAIL FROM:asdff@asdf.com<CR><LF> */
1959 uint8_t request2[] = {
1960 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
1961 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
1962 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
1963 0x0d, 0x0a
1964 };
1965 uint32_t request2_len = sizeof(request2);
1966 /* 250 2.1.0 Ok<CR><LF> */
1967 uint8_t reply2[] = {
1968 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
1969 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
1970 };
1971 uint32_t reply2_len = sizeof(reply2);
1972
1973 /* RCPT TO:bimbs@gmail.com<CR><LF> */
1974 uint8_t request3[] = {
1975 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
1976 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
1977 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
1978 0x0a
1979 };
1980 uint32_t request3_len = sizeof(request3);
1981 /* 250 2.1.5 Ok<CR><LF> */
1982 uint8_t reply3[] = {
1983 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
1984 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
1985 };
1986 uint32_t reply3_len = sizeof(reply3);
1987
1988 /* DATA<CR><LF> */
1989 uint8_t request4[] = {
1990 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
1991 };
1992 uint32_t request4_len = sizeof(request4);
1993 /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
1994 uint8_t reply4[] = {
1995 0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
1996 0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
1997 0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
1998 0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
1999 0x4c, 0x46, 0x3e, 0x0d, 0x0a
2000 };
2001 uint32_t reply4_len = sizeof(reply4);
2002
2003 /* FROM:asdff@asdf.com<CR><LF> */
2004 uint8_t request5_1[] = {
2005 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
2006 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
2007 0x63, 0x6f, 0x6d, 0x0d, 0x0a
2008 };
2009 uint32_t request5_1_len = sizeof(request5_1);
2010 /* TO:bimbs@gmail.com<CR><LF> */
2011 uint8_t request5_2[] = {
2012 0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73,
2013 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63,
2014 0x6f, 0x6d, 0x0d, 0x0a
2015 };
2016 uint32_t request5_2_len = sizeof(request5_2);
2017 /* <CR><LF> */
2018 uint8_t request5_3[] = {
2019 0x0d, 0x0a
2020 };
2021 uint32_t request5_3_len = sizeof(request5_3);
2022 /* this is test mail1<CR><LF> */
2023 uint8_t request5_4[] = {
2024 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
2025 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x69,
2026 0x6c, 0x31, 0x0d, 0x0a
2027 };
2028 uint32_t request5_4_len = sizeof(request5_4);
2029 /* .<CR><LF> */
2030 uint8_t request5_5[] = {
2031 0x2e, 0x0d, 0x0a
2032 };
2033 uint32_t request5_5_len = sizeof(request5_5);
2034 /* 250 2.0.0 Ok: queued as 6A1AF20BF2<CR><LF> */
2035 uint8_t reply5[] = {
2036 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
2037 0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
2038 0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
2039 0x36, 0x41, 0x31, 0x41, 0x46, 0x32, 0x30, 0x42,
2040 0x46, 0x32, 0x0d, 0x0a
2041 };
2042 uint32_t reply5_len = sizeof(reply5);
2043
2044 /* MAIL FROM:asdfg@asdf.com<CR><LF> */
2045 uint8_t request6[] = {
2046 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
2047 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x67, 0x40,
2048 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
2049 0x0d, 0x0a
2050 };
2051 uint32_t request6_len = sizeof(request6);
2052 /* 250 2.1.0 Ok<CR><LF> */
2053 uint8_t reply6[] = {
2054 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2055 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2056 };
2057 uint32_t reply6_len = sizeof(reply6);
2058
2059 /* RCPT TO:bimbs@gmail.com<CR><LF> */
2060 uint8_t request7[] = {
2061 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
2062 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
2063 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
2064 0x0a
2065 };
2066 uint32_t request7_len = sizeof(request7);
2067 /* 250 2.1.5 Ok<CR><LF> */
2068 uint8_t reply7[] = {
2069 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2070 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2071 };
2072 uint32_t reply7_len = sizeof(reply7);
2073
2074 /* DATA<CR><LF> */
2075 uint8_t request8[] = {
2076 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
2077 };
2078 uint32_t request8_len = sizeof(request8);
2079 /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
2080 uint8_t reply8[] = {
2081 0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
2082 0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
2083 0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
2084 0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
2085 0x4c, 0x46, 0x3e, 0x0d, 0x0a
2086 };
2087 uint32_t reply8_len = sizeof(reply8);
2088
2089 /* FROM:asdfg@gmail.com<CR><LF> */
2090 uint8_t request9_1[] = {
2091 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
2092 0x66, 0x67, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c,
2093 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
2094 };
2095 uint32_t request9_1_len = sizeof(request9_1);
2096 /* TO:bimbs@gmail.com<CR><LF> */
2097 uint8_t request9_2[] = {
2098 0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73,
2099 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63,
2100 0x6f, 0x6d, 0x0d, 0x0a
2101 };
2102 uint32_t request9_2_len = sizeof(request9_2);
2103 /* <CR><LF> */
2104 uint8_t request9_3[] = {
2105 0x0d, 0x0a
2106 };
2107 uint32_t request9_3_len = sizeof(request9_3);
2108 /* this is test mail2<CR><LF> */
2109 uint8_t request9_4[] = {
2110 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
2111 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x69,
2112 0x6c, 0x32, 0x0d, 0x0a
2113 };
2114 uint32_t request9_4_len = sizeof(request9_4);
2115 /* .<CR><LF> */
2116 uint8_t request9_5[] = {
2117 0x2e, 0x0d, 0x0a
2118 };
2119 uint32_t request9_5_len = sizeof(request9_5);
2120 /* 250 2.0.0 Ok: queued as 28CFF20BF2<CR><LF> */
2121 uint8_t reply9[] = {
2122 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
2123 0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
2124 0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
2125 0x32, 0x38, 0x43, 0x46, 0x46, 0x32, 0x30, 0x42,
2126 0x46, 0x32, 0x0d, 0x0a
2127 };
2128 uint32_t reply9_len = sizeof(reply9);
2129
2130 /* QUIT<CR><LF> */
2131 uint8_t request10[] = {
2132 0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
2133 };
2134 uint32_t request10_len = sizeof(request10);
2135 /* 221 2.0.0 Bye<CR><LF> */
2136 uint8_t reply10[] = {
2137 0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
2138 0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
2139 };
2140 uint32_t reply10_len = sizeof(reply10);
2141
2142 TcpSession ssn;
8dbf7a0d 2143 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
576ec7da
AS
2144
2145 memset(&f, 0, sizeof(f));
2146 memset(&ssn, 0, sizeof(ssn));
2147
2148 FLOW_INITIALIZE(&f);
2149 f.protoctx = (void *)&ssn;
429c6388 2150 f.proto = IPPROTO_TCP;
576ec7da
AS
2151
2152 StreamTcpInitConfig(TRUE);
e43ce0a9 2153 SMTPTestInitConfig();
576ec7da 2154
6530c3d0 2155 FLOWLOCK_WRLOCK(&f);
675fa564
GL
2156 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2157 STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
576ec7da
AS
2158 if (r != 0) {
2159 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 2160 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
2161 goto end;
2162 }
6530c3d0 2163 FLOWLOCK_UNLOCK(&f);
06904c90 2164 SMTPState *smtp_state = f.alstate;
576ec7da
AS
2165 if (smtp_state == NULL) {
2166 printf("no smtp state: ");
2167 goto end;
2168 }
2169 if (smtp_state->input_len != 0 ||
0d7159b5 2170 smtp_state->cmds_cnt != 0 ||
576ec7da 2171 smtp_state->cmds_idx != 0 ||
0d7159b5 2172 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
576ec7da
AS
2173 printf("smtp parser in inconsistent state\n");
2174 goto end;
2175 }
2176
6530c3d0 2177 FLOWLOCK_WRLOCK(&f);
675fa564
GL
2178 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2179 STREAM_TOSERVER, request1, request1_len);
576ec7da
AS
2180 if (r != 0) {
2181 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 2182 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
2183 goto end;
2184 }
6530c3d0 2185 FLOWLOCK_UNLOCK(&f);
576ec7da 2186 if (smtp_state->input_len != 0 ||
576ec7da
AS
2187 smtp_state->cmds_cnt != 1 ||
2188 smtp_state->cmds_idx != 0 ||
2189 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2190 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2191 printf("smtp parser in inconsistent state\n");
2192 goto end;
2193 }
2194
6530c3d0 2195 FLOWLOCK_WRLOCK(&f);
675fa564
GL
2196 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2197 STREAM_TOCLIENT, reply1, reply1_len);
576ec7da
AS
2198 if (r != 0) {
2199 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 2200 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
2201 goto end;
2202 }
6530c3d0 2203 FLOWLOCK_UNLOCK(&f);
576ec7da 2204 if (smtp_state->input_len != 0 ||
576ec7da
AS
2205 smtp_state->cmds_cnt != 0 ||
2206 smtp_state->cmds_idx != 0 ||
2207 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2208 printf("smtp parser in inconsistent state\n");
2209 goto end;
2210 }
2211
6530c3d0 2212 FLOWLOCK_WRLOCK(&f);
675fa564
GL
2213 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2214 STREAM_TOSERVER, request2, request2_len);
576ec7da
AS
2215 if (r != 0) {
2216 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 2217 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
2218 goto end;
2219 }
6530c3d0 2220 FLOWLOCK_UNLOCK(&f);
576ec7da 2221 if (smtp_state->input_len != 0 ||
576ec7da
AS
2222 smtp_state->cmds_cnt != 1 ||
2223 smtp_state->cmds_idx != 0 ||
2224 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2225 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2226 printf("smtp parser in inconsistent state\n");
2227 goto end;
2228 }
2229
6530c3d0 2230 FLOWLOCK_WRLOCK(&f);
675fa564
GL
2231 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2232 STREAM_TOCLIENT, reply2, reply2_len);
576ec7da
AS
2233 if (r != 0) {
2234 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 2235 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
2236 goto end;
2237 }
6530c3d0 2238 FLOWLOCK_UNLOCK(&f);
576ec7da 2239 if (smtp_state->input_len != 0 ||
576ec7da
AS
2240 smtp_state->cmds_cnt != 0 ||
2241 smtp_state->cmds_idx != 0 ||
2242 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2243 printf("smtp parser in inconsistent state\n");
2244 goto end;
2245 }
2246
6530c3d0 2247 FLOWLOCK_WRLOCK(&f);
675fa564
GL
2248 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2249 STREAM_TOSERVER, request3, request3_len);
576ec7da
AS
2250 if (r != 0) {
2251 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 2252 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
2253 goto end;
2254 }
6530c3d0 2255 FLOWLOCK_UNLOCK(&f);
576ec7da 2256 if (smtp_state->input_len != 0 ||
576ec7da
AS
2257 smtp_state->cmds_cnt != 1 ||
2258 smtp_state->cmds_idx != 0 ||
2259 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2260 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2261 printf("smtp parser in inconsistent state\n");
2262 goto end;
2263 }
2264
6530c3d0 2265 FLOWLOCK_WRLOCK(&f);
675fa564
GL
2266 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2267 STREAM_TOCLIENT, reply3, reply3_len);
576ec7da
AS
2268 if (r != 0) {
2269 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 2270 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
2271 goto end;
2272 }
6530c3d0 2273 FLOWLOCK_UNLOCK(&f);
576ec7da 2274 if (smtp_state->input_len != 0 ||
576ec7da
AS
2275 smtp_state->cmds_cnt != 0 ||
2276 smtp_state->cmds_idx != 0 ||
2277 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2278 printf("smtp parser in inconsistent state\n");
2279 goto end;
2280 }
2281
6530c3d0 2282 FLOWLOCK_WRLOCK(&f);
675fa564
GL
2283 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2284 STREAM_TOSERVER, request4, request4_len);
576ec7da
AS
2285 if (r != 0) {
2286 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 2287 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
2288 goto end;
2289 }
6530c3d0 2290 FLOWLOCK_UNLOCK(&f);
576ec7da 2291 if (smtp_state->input_len != 0 ||
576ec7da
AS
2292 smtp_state->cmds_cnt != 1 ||
2293 smtp_state->cmds_idx != 0 ||
2294 smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
2295 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2296 printf("smtp parser in inconsistent state\n");
2297 goto end;
2298 }
2299
6530c3d0 2300 FLOWLOCK_WRLOCK(&f);
675fa564
GL
2301 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2302 STREAM_TOCLIENT, reply4, reply4_len);
576ec7da
AS
2303 if (r != 0) {
2304 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 2305 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
2306 goto end;
2307 }
6530c3d0 2308 FLOWLOCK_UNLOCK(&f);
576ec7da 2309 if (smtp_state->input_len != 0 ||
576ec7da
AS
2310 smtp_state->cmds_cnt != 0 ||
2311 smtp_state->cmds_idx != 0 ||
2312 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2313 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
2314 printf("smtp parser in inconsistent state\n");
2315 goto end;
2316 }
2317
6530c3d0 2318 FLOWLOCK_WRLOCK(&f);
675fa564
GL
2319 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2320 STREAM_TOSERVER, request5_1, request5_1_len);
576ec7da
AS
2321 if (r != 0) {
2322 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 2323 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
2324 goto end;
2325 }
6530c3d0 2326 FLOWLOCK_UNLOCK(&f);
576ec7da 2327 if (smtp_state->input_len != 0 ||
576ec7da
AS
2328 smtp_state->cmds_cnt != 0 ||
2329 smtp_state->cmds_idx != 0 ||
2330 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2331 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
2332
2333 printf("smtp parser in inconsistent state\n");
2334 goto end;
2335 }
2336
6530c3d0 2337 FLOWLOCK_WRLOCK(&f);
675fa564
GL
2338 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2339 STREAM_TOSERVER, request5_2, request5_2_len);
576ec7da
AS
2340 if (r != 0) {
2341 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 2342 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
2343 goto end;
2344 }
6530c3d0 2345 FLOWLOCK_UNLOCK(&f);
576ec7da 2346 if (smtp_state->input_len != 0 ||
576ec7da
AS
2347 smtp_state->cmds_cnt != 0 ||
2348 smtp_state->cmds_idx != 0 ||
2349 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2350 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
2351
2352 printf("smtp parser in inconsistent state\n");
2353 goto end;
2354 }
2355
6530c3d0 2356 FLOWLOCK_WRLOCK(&f);
675fa564
GL
2357 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2358 STREAM_TOSERVER, request5_3, request5_3_len);
576ec7da
AS
2359 if (r != 0) {
2360 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 2361 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
2362 goto end;
2363 }
6530c3d0 2364 FLOWLOCK_UNLOCK(&f);
576ec7da 2365 if (smtp_state->input_len != 0 ||
576ec7da
AS
2366 smtp_state->cmds_cnt != 0 ||
2367 smtp_state->cmds_idx != 0 ||
2368 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2369 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
2370
2371 printf("smtp parser in inconsistent state\n");
2372 goto end;
2373 }
2374
6530c3d0 2375 FLOWLOCK_WRLOCK(&f);
675fa564
GL
2376 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2377 STREAM_TOSERVER, request5_4, request5_4_len);
576ec7da
AS
2378 if (r != 0) {
2379 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 2380 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
2381 goto end;
2382 }
6530c3d0 2383 FLOWLOCK_UNLOCK(&f);
576ec7da 2384 if (smtp_state->input_len != 0 ||
576ec7da
AS
2385 smtp_state->cmds_cnt != 0 ||
2386 smtp_state->cmds_idx != 0 ||
2387 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2388 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
2389
2390 printf("smtp parser in inconsistent state\n");
2391 goto end;
2392 }
2393
6530c3d0 2394 FLOWLOCK_WRLOCK(&f);
675fa564
GL
2395 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2396 STREAM_TOSERVER, request5_5, request5_5_len);
576ec7da
AS
2397 if (r != 0) {
2398 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 2399 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
2400 goto end;
2401 }
6530c3d0 2402 FLOWLOCK_UNLOCK(&f);
576ec7da 2403 if (smtp_state->input_len != 0 ||
576ec7da
AS
2404 smtp_state->cmds_cnt != 1 ||
2405 smtp_state->cmds_idx != 0 ||
2406 smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
2407 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2408 printf("smtp parser in inconsistent state\n");
2409 goto end;
2410 }
2411
6530c3d0 2412 FLOWLOCK_WRLOCK(&f);
675fa564
GL
2413 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2414 STREAM_TOCLIENT, reply5, reply5_len);
576ec7da
AS
2415 if (r != 0) {
2416 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 2417 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
2418 goto end;
2419 }
6530c3d0 2420 FLOWLOCK_UNLOCK(&f);
576ec7da 2421 if (smtp_state->input_len != 0 ||
576ec7da
AS
2422 smtp_state->cmds_cnt != 0 ||
2423 smtp_state->cmds_idx != 0 ||
2424 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2425 printf("smtp parser in inconsistent state\n");
2426 goto end;
2427 }
2428
6530c3d0 2429 FLOWLOCK_WRLOCK(&f);
675fa564
GL
2430 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2431 STREAM_TOSERVER, request6, request6_len);
576ec7da
AS
2432 if (r != 0) {
2433 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 2434 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
2435 goto end;
2436 }
6530c3d0 2437 FLOWLOCK_UNLOCK(&f);
576ec7da 2438 if (smtp_state->input_len != 0 ||
576ec7da
AS
2439 smtp_state->cmds_cnt != 1 ||
2440 smtp_state->cmds_idx != 0 ||
2441 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2442 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2443 printf("smtp parser in inconsistent state\n");
2444 goto end;
2445 }
2446
6530c3d0 2447 FLOWLOCK_WRLOCK(&f);
675fa564
GL
2448 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2449 STREAM_TOCLIENT, reply6, reply6_len);
576ec7da
AS
2450 if (r != 0) {
2451 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 2452 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
2453 goto end;
2454 }
6530c3d0 2455 FLOWLOCK_UNLOCK(&f);
576ec7da 2456 if (smtp_state->input_len != 0 ||
576ec7da
AS
2457 smtp_state->cmds_cnt != 0 ||
2458 smtp_state->cmds_idx != 0 ||
2459 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2460 printf("smtp parser in inconsistent state\n");
2461 goto end;
2462 }
2463
6530c3d0 2464 FLOWLOCK_WRLOCK(&f);
675fa564
GL
2465 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2466 STREAM_TOSERVER, request7, request7_len);
576ec7da
AS
2467 if (r != 0) {
2468 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 2469 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
2470 goto end;
2471 }
6530c3d0 2472 FLOWLOCK_UNLOCK(&f);
576ec7da 2473 if (smtp_state->input_len != 0 ||
576ec7da
AS
2474 smtp_state->cmds_cnt != 1 ||
2475 smtp_state->cmds_idx != 0 ||
2476 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2477 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2478 printf("smtp parser in inconsistent state\n");
2479 goto end;
2480 }
2481
6530c3d0 2482 FLOWLOCK_WRLOCK(&f);
675fa564
GL
2483 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2484 STREAM_TOCLIENT, reply7, reply7_len);
576ec7da
AS
2485 if (r != 0) {
2486 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 2487 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
2488 goto end;
2489 }
6530c3d0 2490 FLOWLOCK_UNLOCK(&f);
576ec7da 2491 if (smtp_state->input_len != 0 ||
576ec7da
AS
2492 smtp_state->cmds_cnt != 0 ||
2493 smtp_state->cmds_idx != 0 ||
2494 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2495 printf("smtp parser in inconsistent state\n");
2496 goto end;
2497 }
2498
6530c3d0 2499 FLOWLOCK_WRLOCK(&f);
675fa564
GL
2500 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2501 STREAM_TOSERVER, request8, request8_len);
576ec7da
AS
2502 if (r != 0) {
2503 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 2504 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
2505 goto end;
2506 }
6530c3d0 2507 FLOWLOCK_UNLOCK(&f);
576ec7da 2508 if (smtp_state->input_len != 0 ||
576ec7da
AS
2509 smtp_state->cmds_cnt != 1 ||
2510 smtp_state->cmds_idx != 0 ||
2511 smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
2512 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2513 printf("smtp parser in inconsistent state\n");
2514 goto end;
2515 }
2516
6530c3d0 2517 FLOWLOCK_WRLOCK(&f);
675fa564
GL
2518 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2519 STREAM_TOCLIENT, reply8, reply8_len);
576ec7da
AS
2520 if (r != 0) {
2521 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 2522 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
2523 goto end;
2524 }
6530c3d0 2525 FLOWLOCK_UNLOCK(&f);
576ec7da 2526 if (smtp_state->input_len != 0 ||
576ec7da
AS
2527 smtp_state->cmds_cnt != 0 ||
2528 smtp_state->cmds_idx != 0 ||
2529 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2530 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
2531 printf("smtp parser in inconsistent state\n");
2532 goto end;
2533 }
2534
6530c3d0 2535 FLOWLOCK_WRLOCK(&f);
675fa564
GL
2536 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2537 STREAM_TOSERVER, request9_1, request9_1_len);
576ec7da
AS
2538 if (r != 0) {
2539 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 2540 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
2541 goto end;
2542 }
6530c3d0 2543 FLOWLOCK_UNLOCK(&f);
576ec7da 2544 if (smtp_state->input_len != 0 ||
576ec7da
AS
2545 smtp_state->cmds_cnt != 0 ||
2546 smtp_state->cmds_idx != 0 ||
2547 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2548 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
2549
2550 printf("smtp parser in inconsistent state\n");
2551 goto end;
2552 }
2553
6530c3d0 2554 FLOWLOCK_WRLOCK(&f);
675fa564
GL
2555 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2556 STREAM_TOSERVER, request9_2, request9_2_len);
576ec7da
AS
2557 if (r != 0) {
2558 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 2559 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
2560 goto end;
2561 }
6530c3d0 2562 FLOWLOCK_UNLOCK(&f);
576ec7da 2563 if (smtp_state->input_len != 0 ||
576ec7da
AS
2564 smtp_state->cmds_cnt != 0 ||
2565 smtp_state->cmds_idx != 0 ||
2566 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2567 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
2568
2569 printf("smtp parser in inconsistent state\n");
2570 goto end;
2571 }
2572
6530c3d0 2573 FLOWLOCK_WRLOCK(&f);
675fa564
GL
2574 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2575 STREAM_TOSERVER, request9_3, request9_3_len);
576ec7da
AS
2576 if (r != 0) {
2577 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 2578 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
2579 goto end;
2580 }
6530c3d0 2581 FLOWLOCK_UNLOCK(&f);
576ec7da 2582 if (smtp_state->input_len != 0 ||
576ec7da
AS
2583 smtp_state->cmds_cnt != 0 ||
2584 smtp_state->cmds_idx != 0 ||
2585 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2586 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
2587
2588 printf("smtp parser in inconsistent state\n");
2589 goto end;
2590 }
2591
6530c3d0 2592 FLOWLOCK_WRLOCK(&f);
675fa564
GL
2593 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2594 STREAM_TOSERVER, request9_4, request9_4_len);
576ec7da
AS
2595 if (r != 0) {
2596 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 2597 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
2598 goto end;
2599 }
6530c3d0 2600 FLOWLOCK_UNLOCK(&f);
576ec7da 2601 if (smtp_state->input_len != 0 ||
576ec7da
AS
2602 smtp_state->cmds_cnt != 0 ||
2603 smtp_state->cmds_idx != 0 ||
2604 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2605 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
2606
2607 printf("smtp parser in inconsistent state\n");
2608 goto end;
2609 }
2610
6530c3d0 2611 FLOWLOCK_WRLOCK(&f);
675fa564
GL
2612 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2613 STREAM_TOSERVER, request9_5, request9_5_len);
576ec7da
AS
2614 if (r != 0) {
2615 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 2616 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
2617 goto end;
2618 }
6530c3d0 2619 FLOWLOCK_UNLOCK(&f);
576ec7da 2620 if (smtp_state->input_len != 0 ||
576ec7da
AS
2621 smtp_state->cmds_cnt != 1 ||
2622 smtp_state->cmds_idx != 0 ||
2623 smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
2624 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2625 printf("smtp parser in inconsistent state\n");
2626 goto end;
2627 }
2628
6530c3d0 2629 FLOWLOCK_WRLOCK(&f);
675fa564
GL
2630 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2631 STREAM_TOCLIENT, reply9, reply9_len);
576ec7da
AS
2632 if (r != 0) {
2633 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 2634 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
2635 goto end;
2636 }
6530c3d0 2637 FLOWLOCK_UNLOCK(&f);
576ec7da 2638 if (smtp_state->input_len != 0 ||
576ec7da
AS
2639 smtp_state->cmds_cnt != 0 ||
2640 smtp_state->cmds_idx != 0 ||
2641 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2642 printf("smtp parser in inconsistent state\n");
2643 goto end;
2644 }
2645
6530c3d0 2646 FLOWLOCK_WRLOCK(&f);
675fa564
GL
2647 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2648 STREAM_TOSERVER, request10, request10_len);
576ec7da
AS
2649 if (r != 0) {
2650 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 2651 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
2652 goto end;
2653 }
6530c3d0 2654 FLOWLOCK_UNLOCK(&f);
576ec7da 2655 if (smtp_state->input_len != 0 ||
576ec7da
AS
2656 smtp_state->cmds_cnt != 1 ||
2657 smtp_state->cmds_idx != 0 ||
2658 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2659 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2660 printf("smtp parser in inconsistent state\n");
2661 goto end;
2662 }
2663
6530c3d0 2664 FLOWLOCK_WRLOCK(&f);
675fa564
GL
2665 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2666 STREAM_TOCLIENT, reply10, reply10_len);
576ec7da
AS
2667 if (r != 0) {
2668 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 2669 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
2670 goto end;
2671 }
6530c3d0 2672 FLOWLOCK_UNLOCK(&f);
576ec7da 2673 if (smtp_state->input_len != 0 ||
576ec7da
AS
2674 smtp_state->cmds_cnt != 0 ||
2675 smtp_state->cmds_idx != 0 ||
2676 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2677 printf("smtp parser in inconsistent state\n");
2678 goto end;
2679 }
2680
2681 result = 1;
2682end:
429c6388 2683 if (alp_tctx != NULL)
fdefb65b 2684 AppLayerParserThreadCtxFree(alp_tctx);
576ec7da
AS
2685 StreamTcpFreeConfig(TRUE);
2686 FLOW_DESTROY(&f);
2687 return result;
2688}
2689
2690/**
2691 * \test Testing parsing pipelined commands.
2692 */
e43ce0a9 2693static int SMTPParserTest03(void)
576ec7da
AS
2694{
2695 int result = 0;
2696 Flow f;
2697 int r = 0;
2698
2699 /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
2700 uint8_t welcome_reply[] = {
2701 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
2702 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2703 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2704 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
2705 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
2706 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
2707 };
2708 uint32_t welcome_reply_len = sizeof(welcome_reply);
2709
2710 /* EHLO boo.com<CR><LF> */
2711 uint8_t request1[] = {
2712 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
2713 0x2e, 0x63, 0x6f, 0x6d, 0x0a
2714 };
2715 uint32_t request1_len = sizeof(request1);
2716 /* 250-poona_slack_vm1.localdomain<CR><LF>
2717 * 250-PIPELINING<CR><LF>
2718 * 250-SIZE 10240000<CR><LF>
2719 * 250-VRFY<CR><LF>
2720 * 250-ETRN<CR><LF>
2721 * 250-ENHANCEDSTATUSCODES<CR><LF>
2722 * 250-8BITMIME<CR><LF>
2723 * 250 DSN<CR><LF>
2724 */
2725 uint8_t reply1[] = {
2726 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
2727 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2728 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2729 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
2730 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
2731 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
2732 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
2733 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
2734 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
2735 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
2736 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
2737 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
2738 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
2739 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
2740 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
2741 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
2742 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
2743 };
2744 uint32_t reply1_len = sizeof(reply1);
2745
2746 /* MAIL FROM:pbsf@asdfs.com<CR><LF>
2747 * RCPT TO:pbsf@asdfs.com<CR><LF>
2748 * DATA<CR><LF>
2749 */
2750 uint8_t request2[] = {
2751 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
2752 0x4d, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
2753 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
2754 0x0d, 0x0a, 0x52, 0x43, 0x50, 0x54, 0x20, 0x54,
2755 0x4f, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
2756 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
2757 0x0d, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
2758 };
2759 uint32_t request2_len = sizeof(request2);
2760 /* 250 2.1.0 Ok<CR><LF>
2761 * 250 2.1.5 Ok<CR><LF>
2762 * 354 End data with <CR><LF>.<CR><LF>|<CR><LF>|
2763 */
2764 uint8_t reply2[] = {
2765 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2766 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a, 0x32, 0x35,
2767 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, 0x35, 0x20,
2768 0x4f, 0x6b, 0x0d, 0x0a, 0x33, 0x35, 0x34, 0x20,
2769 0x45, 0x6e, 0x64, 0x20, 0x64, 0x61, 0x74, 0x61,
2770 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x3c, 0x43,
2771 0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x2e, 0x3c,
2772 0x43, 0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x0d,
2773 0x0a
2774 };
2775 uint32_t reply2_len = sizeof(reply2);
2776
2777 TcpSession ssn;
8dbf7a0d 2778 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
576ec7da
AS
2779
2780 memset(&f, 0, sizeof(f));
2781 memset(&ssn, 0, sizeof(ssn));
2782
2783 FLOW_INITIALIZE(&f);
2784 f.protoctx = (void *)&ssn;
429c6388 2785 f.proto = IPPROTO_TCP;
576ec7da
AS
2786
2787 StreamTcpInitConfig(TRUE);
e43ce0a9 2788 SMTPTestInitConfig();
576ec7da 2789
6530c3d0 2790 FLOWLOCK_WRLOCK(&f);
675fa564
GL
2791 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2792 STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
576ec7da
AS
2793 if (r != 0) {
2794 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 2795 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
2796 goto end;
2797 }
6530c3d0 2798 FLOWLOCK_UNLOCK(&f);
06904c90 2799 SMTPState *smtp_state = f.alstate;
576ec7da
AS
2800 if (smtp_state == NULL) {
2801 printf("no smtp state: ");
2802 goto end;
2803 }
2804 if (smtp_state->input_len != 0 ||
0d7159b5 2805 smtp_state->cmds_cnt != 0 ||
576ec7da 2806 smtp_state->cmds_idx != 0 ||
0d7159b5 2807 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
576ec7da
AS
2808 printf("smtp parser in inconsistent state\n");
2809 goto end;
2810 }
2811
6530c3d0 2812 FLOWLOCK_WRLOCK(&f);
675fa564
GL
2813 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2814 STREAM_TOSERVER, request1, request1_len);
576ec7da
AS
2815 if (r != 0) {
2816 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 2817 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
2818 goto end;
2819 }
6530c3d0 2820 FLOWLOCK_UNLOCK(&f);
576ec7da 2821 if (smtp_state->input_len != 0 ||
576ec7da
AS
2822 smtp_state->cmds_cnt != 1 ||
2823 smtp_state->cmds_idx != 0 ||
2824 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2825 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2826 printf("smtp parser in inconsistent state\n");
2827 goto end;
2828 }
2829
6530c3d0 2830 FLOWLOCK_WRLOCK(&f);
675fa564
GL
2831 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2832 STREAM_TOCLIENT, reply1, reply1_len);
576ec7da
AS
2833 if (r != 0) {
2834 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 2835 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
2836 goto end;
2837 }
6530c3d0 2838 FLOWLOCK_UNLOCK(&f);
576ec7da 2839 if (smtp_state->input_len != 0 ||
576ec7da
AS
2840 smtp_state->cmds_cnt != 0 ||
2841 smtp_state->cmds_idx != 0 ||
2842 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2843 printf("smtp parser in inconsistent state\n");
2844 goto end;
2845 }
2846
6530c3d0 2847 FLOWLOCK_WRLOCK(&f);
675fa564
GL
2848 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2849 STREAM_TOSERVER, request2, request2_len);
576ec7da
AS
2850 if (r != 0) {
2851 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 2852 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
2853 goto end;
2854 }
6530c3d0 2855 FLOWLOCK_UNLOCK(&f);
576ec7da 2856 if (smtp_state->input_len != 0 ||
576ec7da
AS
2857 smtp_state->cmds_cnt != 3 ||
2858 smtp_state->cmds_idx != 0 ||
2859 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2860 smtp_state->cmds[1] != SMTP_COMMAND_OTHER_CMD ||
2861 smtp_state->cmds[2] != SMTP_COMMAND_DATA ||
2862 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2863 printf("smtp parser in inconsistent state\n");
2864 goto end;
2865 }
2866
6530c3d0 2867 FLOWLOCK_WRLOCK(&f);
675fa564
GL
2868 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2869 STREAM_TOCLIENT, reply2, reply2_len);
576ec7da
AS
2870 if (r != 0) {
2871 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 2872 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
2873 goto end;
2874 }
6530c3d0 2875 FLOWLOCK_UNLOCK(&f);
576ec7da 2876 if (smtp_state->input_len != 0 ||
576ec7da
AS
2877 smtp_state->cmds_cnt != 0 ||
2878 smtp_state->cmds_idx != 0 ||
2879 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2880 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
2881 printf("smtp parser in inconsistent state\n");
2882 goto end;
2883 }
2884
2885 result = 1;
2886end:
429c6388 2887 if (alp_tctx != NULL)
fdefb65b 2888 AppLayerParserThreadCtxFree(alp_tctx);
576ec7da
AS
2889 StreamTcpFreeConfig(TRUE);
2890 FLOW_DESTROY(&f);
2891 return result;
2892}
2893
2894/*
2895 * \test Test smtp with just <LF> delimter instead of <CR><LF>.
2896 */
e43ce0a9 2897static int SMTPParserTest04(void)
576ec7da
AS
2898{
2899 int result = 0;
2900 Flow f;
2901 int r = 0;
2902
2903 /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
2904 uint8_t welcome_reply[] = {
2905 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
2906 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2907 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2908 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
2909 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
2910 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
2911 };
2912 uint32_t welcome_reply_len = sizeof(welcome_reply);
2913
2914 /* EHLO boo.com<CR><LF> */
2915 uint8_t request1[] = {
2916 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
2917 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2918 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2919 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
2920 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
2921 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
2922 };
2923 uint32_t request1_len = sizeof(request1);
2924
2925 TcpSession ssn;
8dbf7a0d 2926 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
576ec7da
AS
2927
2928 memset(&f, 0, sizeof(f));
2929 memset(&ssn, 0, sizeof(ssn));
2930
2931 FLOW_INITIALIZE(&f);
2932 f.protoctx = (void *)&ssn;
429c6388 2933 f.proto = IPPROTO_TCP;
576ec7da
AS
2934
2935 StreamTcpInitConfig(TRUE);
e43ce0a9 2936 SMTPTestInitConfig();
576ec7da 2937
6530c3d0 2938 FLOWLOCK_WRLOCK(&f);
675fa564
GL
2939 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2940 STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
576ec7da
AS
2941 if (r != 0) {
2942 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 2943 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
2944 goto end;
2945 }
6530c3d0 2946 FLOWLOCK_UNLOCK(&f);
06904c90 2947 SMTPState *smtp_state = f.alstate;
576ec7da
AS
2948 if (smtp_state == NULL) {
2949 printf("no smtp state: ");
2950 goto end;
2951 }
2952 if (smtp_state->input_len != 0 ||
0d7159b5 2953 smtp_state->cmds_cnt != 0 ||
576ec7da 2954 smtp_state->cmds_idx != 0 ||
0d7159b5 2955 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
576ec7da
AS
2956 printf("smtp parser in inconsistent state\n");
2957 goto end;
2958 }
2959
6530c3d0 2960 FLOWLOCK_WRLOCK(&f);
675fa564
GL
2961 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2962 STREAM_TOSERVER, request1, request1_len);
576ec7da
AS
2963 if (r != 0) {
2964 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 2965 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
2966 goto end;
2967 }
6530c3d0 2968 FLOWLOCK_UNLOCK(&f);
576ec7da 2969 if (smtp_state->input_len != 0 ||
576ec7da
AS
2970 smtp_state->cmds_cnt != 1 ||
2971 smtp_state->cmds_idx != 0 ||
2972 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2973 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2974 printf("smtp parser in inconsistent state\n");
2975 goto end;
2976 }
2977
2978 result = 1;
2979end:
429c6388 2980 if (alp_tctx != NULL)
fdefb65b 2981 AppLayerParserThreadCtxFree(alp_tctx);
576ec7da
AS
2982 StreamTcpFreeConfig(TRUE);
2983 FLOW_DESTROY(&f);
2984 return result;
2985}
2986
2987/*
2988 * \test Test STARTTLS fail.
2989 */
e43ce0a9 2990static int SMTPParserTest05(void)
576ec7da
AS
2991{
2992 int result = 0;
2993 Flow f;
2994 int r = 0;
2995
2996 /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
2997 uint8_t welcome_reply[] = {
2998 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
2999 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3000 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3001 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
3002 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
3003 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
3004 };
3005 uint32_t welcome_reply_len = sizeof(welcome_reply);
3006
3007 /* EHLO boo.com<CR><LF> */
3008 uint8_t request1[] = {
3009 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3010 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
3011 };
3012 uint32_t request1_len = sizeof(request1);
3013 /* 250-poona_slack_vm1.localdomain<CR><LF>
3014 * 250-PIPELINING<CR><LF>
3015 * 250-SIZE 10240000<CR><LF>
3016 * 250-VRFY<CR><LF>
3017 * 250-ETRN<CR><LF>
3018 * 250-ENHANCEDSTATUSCODES<CR><LF>
3019 * 250-8BITMIME<CR><LF>
3020 * 250 DSN<CR><LF>
3021 */
3022 uint8_t reply1[] = {
3023 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
3024 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3025 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3026 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
3027 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
3028 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
3029 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
3030 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
3031 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3032 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
3033 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
3034 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
3035 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
3036 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
3037 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
3038 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
3039 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
3040 };
3041 uint32_t reply1_len = sizeof(reply1);
3042
3043 /* STARTTLS<CR><LF> */
3044 uint8_t request2[] = {
3045 0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
3046 0x0d, 0x0a
3047 };
3048 uint32_t request2_len = sizeof(request2);
3049 /* 502 5.5.2 Error: command not recognized<CR><LF> */
3050 uint8_t reply2[] = {
3051 0x35, 0x30, 0x32, 0x20, 0x35, 0x2e, 0x35, 0x2e,
3052 0x32, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x3a,
3053 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
3054 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x63,
3055 0x6f, 0x67, 0x6e, 0x69, 0x7a, 0x65, 0x64, 0x0d,
3056 0x0a
3057 };
3058 uint32_t reply2_len = sizeof(reply2);
3059
3060 /* QUIT<CR><LF> */
3061 uint8_t request3[] = {
3062 0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
3063
3064 };
3065 uint32_t request3_len = sizeof(request3);
3066 /* 221 2.0.0 Bye<CR><LF> */
3067 uint8_t reply3[] = {
3068 0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
3069 0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
3070 };
3071 uint32_t reply3_len = sizeof(reply3);
3072
3073 TcpSession ssn;
8dbf7a0d 3074 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
576ec7da
AS
3075
3076 memset(&f, 0, sizeof(f));
3077 memset(&ssn, 0, sizeof(ssn));
3078
3079 FLOW_INITIALIZE(&f);
3080 f.protoctx = (void *)&ssn;
429c6388 3081 f.proto = IPPROTO_TCP;
576ec7da
AS
3082
3083 StreamTcpInitConfig(TRUE);
e43ce0a9 3084 SMTPTestInitConfig();
576ec7da 3085
6530c3d0 3086 FLOWLOCK_WRLOCK(&f);
675fa564
GL
3087 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3088 STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
576ec7da
AS
3089 if (r != 0) {
3090 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 3091 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
3092 goto end;
3093 }
6530c3d0 3094 FLOWLOCK_UNLOCK(&f);
06904c90 3095 SMTPState *smtp_state = f.alstate;
576ec7da
AS
3096 if (smtp_state == NULL) {
3097 printf("no smtp state: ");
3098 goto end;
3099 }
3100 if (smtp_state->input_len != 0 ||
0d7159b5 3101 smtp_state->cmds_cnt != 0 ||
576ec7da 3102 smtp_state->cmds_idx != 0 ||
0d7159b5 3103 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
576ec7da
AS
3104 printf("smtp parser in inconsistent state\n");
3105 goto end;
3106 }
3107
6530c3d0 3108 FLOWLOCK_WRLOCK(&f);
675fa564
GL
3109 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3110 STREAM_TOSERVER, request1, request1_len);
576ec7da
AS
3111 if (r != 0) {
3112 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 3113 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
3114 goto end;
3115 }
6530c3d0 3116 FLOWLOCK_UNLOCK(&f);
576ec7da 3117 if (smtp_state->input_len != 0 ||
576ec7da
AS
3118 smtp_state->cmds_cnt != 1 ||
3119 smtp_state->cmds_idx != 0 ||
3120 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3121 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
3122 printf("smtp parser in inconsistent state\n");
3123 goto end;
3124 }
3125
6530c3d0 3126 FLOWLOCK_WRLOCK(&f);
675fa564
GL
3127 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3128 STREAM_TOCLIENT, reply1, reply1_len);
576ec7da
AS
3129 if (r != 0) {
3130 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 3131 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
3132 goto end;
3133 }
6530c3d0 3134 FLOWLOCK_UNLOCK(&f);
576ec7da 3135 if (smtp_state->input_len != 0 ||
576ec7da
AS
3136 smtp_state->cmds_cnt != 0 ||
3137 smtp_state->cmds_idx != 0 ||
3138 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
3139 printf("smtp parser in inconsistent state\n");
3140 goto end;
3141 }
3142
6530c3d0 3143 FLOWLOCK_WRLOCK(&f);
675fa564
GL
3144 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3145 STREAM_TOSERVER, request2, request2_len);
576ec7da
AS
3146 if (r != 0) {
3147 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 3148 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
3149 goto end;
3150 }
6530c3d0 3151 FLOWLOCK_UNLOCK(&f);
576ec7da 3152 if (smtp_state->input_len != 0 ||
576ec7da
AS
3153 smtp_state->cmds_cnt != 1 ||
3154 smtp_state->cmds_idx != 0 ||
3155 smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS ||
3156 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
3157 printf("smtp parser in inconsistent state\n");
3158 goto end;
3159 }
3160
6530c3d0 3161 FLOWLOCK_WRLOCK(&f);
675fa564
GL
3162 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3163 STREAM_TOCLIENT, reply2, reply2_len);
576ec7da
AS
3164 if (r != 0) {
3165 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 3166 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
3167 goto end;
3168 }
6530c3d0 3169 FLOWLOCK_UNLOCK(&f);
576ec7da 3170 if (smtp_state->input_len != 0 ||
576ec7da
AS
3171 smtp_state->cmds_cnt != 0 ||
3172 smtp_state->cmds_idx != 0 ||
3173 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
3174 printf("smtp parser in inconsistent state\n");
3175 goto end;
3176 }
3177
3178 if ((f.flags & FLOW_NOPAYLOAD_INSPECTION) ||
c1558f5a 3179 (ssn.flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) ||
576ec7da
AS
3180 (((TcpSession *)f.protoctx)->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) ||
3181 (((TcpSession *)f.protoctx)->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
3182 goto end;
3183 }
3184
6530c3d0 3185 FLOWLOCK_WRLOCK(&f);
675fa564
GL
3186 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3187 STREAM_TOSERVER, request3, request3_len);
576ec7da
AS
3188 if (r != 0) {
3189 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 3190 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
3191 goto end;
3192 }
6530c3d0 3193 FLOWLOCK_UNLOCK(&f);
576ec7da 3194 if (smtp_state->input_len != 0 ||
576ec7da
AS
3195 smtp_state->cmds_cnt != 1 ||
3196 smtp_state->cmds_idx != 0 ||
3197 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3198 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
3199 printf("smtp parser in inconsistent state\n");
3200 goto end;
3201 }
3202
6530c3d0 3203 FLOWLOCK_WRLOCK(&f);
675fa564
GL
3204 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3205 STREAM_TOCLIENT, reply3, reply3_len);
576ec7da
AS
3206 if (r != 0) {
3207 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 3208 FLOWLOCK_UNLOCK(&f);
576ec7da
AS
3209 goto end;
3210 }
6530c3d0 3211 FLOWLOCK_UNLOCK(&f);
576ec7da 3212 if (smtp_state->input_len != 0 ||
576ec7da
AS
3213 smtp_state->cmds_cnt != 0 ||
3214 smtp_state->cmds_idx != 0 ||
3215 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
3216 printf("smtp parser in inconsistent state\n");
3217 goto end;
3218 }
3219
3220 result = 1;
3221end:
429c6388 3222 if (alp_tctx != NULL)
fdefb65b 3223 AppLayerParserThreadCtxFree(alp_tctx);
576ec7da
AS
3224 StreamTcpFreeConfig(TRUE);
3225 FLOW_DESTROY(&f);
3226 return result;
3227}
3228
d3ca65de
AS
3229/**
3230 * \test Test multiple DATA commands(full mail transactions).
3231 */
e43ce0a9 3232static int SMTPParserTest06(void)
d3ca65de
AS
3233{
3234 int result = 0;
3235 Flow f;
3236 int r = 0;
3237
3238 uint8_t welcome_reply[] = {
3239 0x32, 0x32, 0x30, 0x20, 0x62, 0x61, 0x79, 0x30,
3240 0x2d, 0x6d, 0x63, 0x36, 0x2d, 0x66, 0x31, 0x30,
3241 0x2e, 0x62, 0x61, 0x79, 0x30, 0x2e, 0x68, 0x6f,
3242 0x74, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f,
3243 0x6d, 0x20, 0x53, 0x65, 0x6e, 0x64, 0x69, 0x6e,
3244 0x67, 0x20, 0x75, 0x6e, 0x73, 0x6f, 0x6c, 0x69,
3245 0x63, 0x69, 0x74, 0x65, 0x64, 0x20, 0x63, 0x6f,
3246 0x6d, 0x6d, 0x65, 0x72, 0x63, 0x69, 0x61, 0x6c,
3247 0x20, 0x6f, 0x72, 0x20, 0x62, 0x75, 0x6c, 0x6b,
3248 0x20, 0x65, 0x2d, 0x6d, 0x61, 0x69, 0x6c, 0x20,
3249 0x74, 0x6f, 0x20, 0x4d, 0x69, 0x63, 0x72, 0x6f,
3250 0x73, 0x6f, 0x66, 0x74, 0x27, 0x73, 0x20, 0x63,
3251 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x20,
3252 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20,
3253 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x68, 0x69,
3254 0x62, 0x69, 0x74, 0x65, 0x64, 0x2e, 0x20, 0x4f,
3255 0x74, 0x68, 0x65, 0x72, 0x20, 0x72, 0x65, 0x73,
3256 0x74, 0x72, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e,
3257 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x66, 0x6f,
3258 0x75, 0x6e, 0x64, 0x20, 0x61, 0x74, 0x20, 0x68,
3259 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x72,
3260 0x69, 0x76, 0x61, 0x63, 0x79, 0x2e, 0x6d, 0x73,
3261 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x41, 0x6e,
3262 0x74, 0x69, 0x2d, 0x73, 0x70, 0x61, 0x6d, 0x2f,
3263 0x2e, 0x20, 0x56, 0x69, 0x6f, 0x6c, 0x61, 0x74,
3264 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x77, 0x69, 0x6c,
3265 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74,
3266 0x20, 0x69, 0x6e, 0x20, 0x75, 0x73, 0x65, 0x20,
3267 0x6f, 0x66, 0x20, 0x65, 0x71, 0x75, 0x69, 0x70,
3268 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x63,
3269 0x61, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20,
3270 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e,
3271 0x69, 0x61, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6f,
3272 0x74, 0x68, 0x65, 0x72, 0x20, 0x73, 0x74, 0x61,
3273 0x74, 0x65, 0x73, 0x2e, 0x20, 0x46, 0x72, 0x69,
3274 0x2c, 0x20, 0x31, 0x36, 0x20, 0x46, 0x65, 0x62,
3275 0x20, 0x32, 0x30, 0x30, 0x37, 0x20, 0x30, 0x35,
3276 0x3a, 0x30, 0x33, 0x3a, 0x32, 0x33, 0x20, 0x2d,
3277 0x30, 0x38, 0x30, 0x30, 0x20, 0x0d, 0x0a
3278 };
3279 uint32_t welcome_reply_len = sizeof(welcome_reply);
3280
3281 uint8_t request1[] = {
3282 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x45, 0x58, 0x43,
3283 0x48, 0x41, 0x4e, 0x47, 0x45, 0x32, 0x2e, 0x63,
3284 0x67, 0x63, 0x65, 0x6e, 0x74, 0x2e, 0x6d, 0x69,
3285 0x61, 0x6d, 0x69, 0x2e, 0x65, 0x64, 0x75, 0x0d,
3286 0x0a
3287 };
3288 uint32_t request1_len = sizeof(request1);
3289
3290 uint8_t reply1[] = {
3291 0x32, 0x35, 0x30, 0x2d, 0x62, 0x61, 0x79, 0x30,
3292 0x2d, 0x6d, 0x63, 0x36, 0x2d, 0x66, 0x31, 0x30,
3293 0x2e, 0x62, 0x61, 0x79, 0x30, 0x2e, 0x68, 0x6f,
3294 0x74, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f,
3295 0x6d, 0x20, 0x28, 0x33, 0x2e, 0x33, 0x2e, 0x31,
3296 0x2e, 0x34, 0x29, 0x20, 0x48, 0x65, 0x6c, 0x6c,
3297 0x6f, 0x20, 0x5b, 0x31, 0x32, 0x39, 0x2e, 0x31,
3298 0x37, 0x31, 0x2e, 0x33, 0x32, 0x2e, 0x35, 0x39,
3299 0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53,
3300 0x49, 0x5a, 0x45, 0x20, 0x32, 0x39, 0x36, 0x39,
3301 0x36, 0x30, 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35,
3302 0x30, 0x2d, 0x50, 0x49, 0x50, 0x45, 0x4c, 0x49,
3303 0x4e, 0x49, 0x4e, 0x47, 0x0d, 0x0a, 0x32, 0x35,
3304 0x30, 0x2d, 0x38, 0x62, 0x69, 0x74, 0x6d, 0x69,
3305 0x6d, 0x65, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3306 0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x4d, 0x49,
3307 0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3308 0x43, 0x48, 0x55, 0x4e, 0x4b, 0x49, 0x4e, 0x47,
3309 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x41, 0x55,
3310 0x54, 0x48, 0x20, 0x4c, 0x4f, 0x47, 0x49, 0x4e,
3311 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x41, 0x55,
3312 0x54, 0x48, 0x3d, 0x4c, 0x4f, 0x47, 0x49, 0x4e,
3313 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20, 0x4f, 0x4b,
3314 0x0d, 0x0a
3315 };
3316 uint32_t reply1_len = sizeof(reply1);
3317
3318 /* MAIL FROM:asdff@asdf.com<CR><LF> */
3319 uint8_t request2[] = {
3320 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
3321 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
3322 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
3323 0x0d, 0x0a
3324 };
3325 uint32_t request2_len = sizeof(request2);
3326 /* 250 2.1.0 Ok<CR><LF> */
3327 uint8_t reply2[] = {
3328 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
3329 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
3330 };
3331 uint32_t reply2_len = sizeof(reply2);
3332
3333 /* RCPT TO:bimbs@gmail.com<CR><LF> */
3334 uint8_t request3[] = {
3335 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
3336 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
3337 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
3338 0x0a
3339 };
3340 uint32_t request3_len = sizeof(request3);
3341 /* 250 2.1.5 Ok<CR><LF> */
3342 uint8_t reply3[] = {
3343 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
3344 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
3345 };
3346 uint32_t reply3_len = sizeof(reply3);
3347
3348 /* BDAT 51<CR><LF> */
3349 uint8_t request4[] = {
3350 0x42, 0x44, 0x41, 0x54, 0x20, 0x35, 0x31, 0x0d,
3351 0x0a,
3352 };
3353 uint32_t request4_len = sizeof(request4);
3354
3355 uint8_t request5[] = {
3356 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
3357 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
3358 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
3359 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x0d, 0x0a,
3360 };
3361 uint32_t request5_len = sizeof(request5);
3362
3363 uint8_t request6[] = {
3364 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
3365 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
3366 0x66, 0x0d, 0x0a,
3367 };
561630d8 3368 uint32_t request6_len = sizeof(request6);
d3ca65de
AS
3369
3370 TcpSession ssn;
8dbf7a0d 3371 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
d3ca65de
AS
3372
3373 memset(&f, 0, sizeof(f));
3374 memset(&ssn, 0, sizeof(ssn));
3375
3376 FLOW_INITIALIZE(&f);
3377 f.protoctx = (void *)&ssn;
429c6388 3378 f.proto = IPPROTO_TCP;
d3ca65de
AS
3379
3380 StreamTcpInitConfig(TRUE);
e43ce0a9 3381 SMTPTestInitConfig();
d3ca65de 3382
6530c3d0 3383 FLOWLOCK_WRLOCK(&f);
675fa564
GL
3384 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3385 STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
d3ca65de
AS
3386 if (r != 0) {
3387 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 3388 FLOWLOCK_UNLOCK(&f);
d3ca65de
AS
3389 goto end;
3390 }
6530c3d0 3391 FLOWLOCK_UNLOCK(&f);
06904c90 3392 SMTPState *smtp_state = f.alstate;
d3ca65de
AS
3393 if (smtp_state == NULL) {
3394 printf("no smtp state: ");
3395 goto end;
3396 }
3397 if (smtp_state->input_len != 0 ||
0d7159b5 3398 smtp_state->cmds_cnt != 0 ||
d3ca65de 3399 smtp_state->cmds_idx != 0 ||
0d7159b5 3400 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
d3ca65de
AS
3401 printf("smtp parser in inconsistent state\n");
3402 goto end;
3403 }
3404
6530c3d0 3405 FLOWLOCK_WRLOCK(&f);
675fa564
GL
3406 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3407 STREAM_TOSERVER, request1, request1_len);
d3ca65de
AS
3408 if (r != 0) {
3409 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 3410 FLOWLOCK_UNLOCK(&f);
d3ca65de
AS
3411 goto end;
3412 }
6530c3d0 3413 FLOWLOCK_UNLOCK(&f);
d3ca65de
AS
3414 if (smtp_state->input_len != 0 ||
3415 smtp_state->cmds_cnt != 1 ||
3416 smtp_state->cmds_idx != 0 ||
3417 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3418 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
3419 printf("smtp parser in inconsistent state\n");
3420 goto end;
3421 }
3422
6530c3d0 3423 FLOWLOCK_WRLOCK(&f);
675fa564
GL
3424 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3425 STREAM_TOCLIENT, reply1, reply1_len);
d3ca65de
AS
3426 if (r != 0) {
3427 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 3428 FLOWLOCK_UNLOCK(&f);
d3ca65de
AS
3429 goto end;
3430 }
6530c3d0 3431 FLOWLOCK_UNLOCK(&f);
d3ca65de
AS
3432 if (smtp_state->input_len != 0 ||
3433 smtp_state->cmds_cnt != 0 ||
3434 smtp_state->cmds_idx != 0 ||
3435 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
3436 printf("smtp parser in inconsistent state\n");
3437 goto end;
3438 }
3439
6530c3d0 3440 FLOWLOCK_WRLOCK(&f);
675fa564
GL
3441 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3442 STREAM_TOSERVER, request2, request2_len);
d3ca65de
AS
3443 if (r != 0) {
3444 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 3445 FLOWLOCK_UNLOCK(&f);
d3ca65de
AS
3446 goto end;
3447 }
6530c3d0 3448 FLOWLOCK_UNLOCK(&f);
d3ca65de
AS
3449 if (smtp_state->input_len != 0 ||
3450 smtp_state->cmds_cnt != 1 ||
3451 smtp_state->cmds_idx != 0 ||
3452 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3453 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
3454 printf("smtp parser in inconsistent state\n");
3455 goto end;
3456 }
3457
6530c3d0 3458 FLOWLOCK_WRLOCK(&f);
675fa564
GL
3459 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3460 STREAM_TOCLIENT, reply2, reply2_len);
d3ca65de
AS
3461 if (r != 0) {
3462 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 3463 FLOWLOCK_UNLOCK(&f);
d3ca65de
AS
3464 goto end;
3465 }
6530c3d0 3466 FLOWLOCK_UNLOCK(&f);
d3ca65de
AS
3467 if (smtp_state->input_len != 0 ||
3468 smtp_state->cmds_cnt != 0 ||
3469 smtp_state->cmds_idx != 0 ||
3470 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
3471 printf("smtp parser in inconsistent state\n");
3472 goto end;
3473 }
3474
6530c3d0 3475 FLOWLOCK_WRLOCK(&f);
675fa564
GL
3476 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3477 STREAM_TOSERVER, request3, request3_len);
d3ca65de
AS
3478 if (r != 0) {
3479 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 3480 FLOWLOCK_UNLOCK(&f);
d3ca65de
AS
3481 goto end;
3482 }
6530c3d0 3483 FLOWLOCK_UNLOCK(&f);
d3ca65de
AS
3484 if (smtp_state->input_len != 0 ||
3485 smtp_state->cmds_cnt != 1 ||
3486 smtp_state->cmds_idx != 0 ||
3487 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3488 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
3489 printf("smtp parser in inconsistent state\n");
3490 goto end;
3491 }
3492
6530c3d0 3493 FLOWLOCK_WRLOCK(&f);
675fa564
GL
3494 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3495 STREAM_TOCLIENT, reply3, reply3_len);
d3ca65de
AS
3496 if (r != 0) {
3497 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 3498 FLOWLOCK_UNLOCK(&f);
d3ca65de
AS
3499 goto end;
3500 }
6530c3d0 3501 FLOWLOCK_UNLOCK(&f);
d3ca65de
AS
3502 if (smtp_state->input_len != 0 ||
3503 smtp_state->cmds_cnt != 0 ||
3504 smtp_state->cmds_idx != 0 ||
3505 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
3506 printf("smtp parser in inconsistent state\n");
3507 goto end;
3508 }
3509
6530c3d0 3510 FLOWLOCK_WRLOCK(&f);
675fa564
GL
3511 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3512 STREAM_TOSERVER, request4, request4_len);
d3ca65de
AS
3513 if (r != 0) {
3514 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 3515 FLOWLOCK_UNLOCK(&f);
d3ca65de
AS
3516 goto end;
3517 }
6530c3d0 3518 FLOWLOCK_UNLOCK(&f);
d3ca65de
AS
3519 if (smtp_state->input_len != 0 ||
3520 smtp_state->cmds_cnt != 1 ||
3521 smtp_state->cmds_idx != 0 ||
3522 smtp_state->cmds[0] != SMTP_COMMAND_BDAT ||
3523 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
3524 SMTP_PARSER_STATE_COMMAND_DATA_MODE) ||
3525 smtp_state->bdat_chunk_len != 51 ||
3526 smtp_state->bdat_chunk_idx != 0) {
3527 printf("smtp parser in inconsistent state\n");
3528 goto end;
3529 }
3530
6530c3d0 3531 FLOWLOCK_WRLOCK(&f);
675fa564
GL
3532 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3533 STREAM_TOSERVER, request5, request5_len);
d3ca65de
AS
3534 if (r != 0) {
3535 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 3536 FLOWLOCK_UNLOCK(&f);
d3ca65de
AS
3537 goto end;
3538 }
6530c3d0 3539 FLOWLOCK_UNLOCK(&f);
d3ca65de
AS
3540 if (smtp_state->input_len != 0 ||
3541 smtp_state->cmds_cnt != 1 ||
3542 smtp_state->cmds_idx != 0 ||
3543 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
3544 SMTP_PARSER_STATE_COMMAND_DATA_MODE) ||
3545 smtp_state->bdat_chunk_len != 51 ||
3546 smtp_state->bdat_chunk_idx != 32) {
3547 printf("smtp parser in inconsistent state\n");
3548 goto end;
3549 }
3550
6530c3d0 3551 FLOWLOCK_WRLOCK(&f);
675fa564
GL
3552 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3553 STREAM_TOSERVER, request6, request6_len);
d3ca65de
AS
3554 if (r != 0) {
3555 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 3556 FLOWLOCK_UNLOCK(&f);
d3ca65de
AS
3557 goto end;
3558 }
6530c3d0 3559 FLOWLOCK_UNLOCK(&f);
d3ca65de
AS
3560 if (smtp_state->input_len != 0 ||
3561 smtp_state->cmds_cnt != 1 ||
3562 smtp_state->cmds_idx != 0 ||
3563 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN ||
3564 smtp_state->bdat_chunk_len != 51 ||
3565 smtp_state->bdat_chunk_idx != 51) {
3566 printf("smtp parser in inconsistent state\n");
3567 goto end;
3568 }
3569
3570 result = 1;
3571end:
429c6388 3572 if (alp_tctx != NULL)
fdefb65b 3573 AppLayerParserThreadCtxFree(alp_tctx);
d3ca65de
AS
3574 StreamTcpFreeConfig(TRUE);
3575 FLOW_DESTROY(&f);
3576 return result;
3577}
3578
4a6908d3
AS
3579/*
3580 * \test Test retrieving lines when frag'ed.
3581 */
e43ce0a9 3582static int SMTPParserTest07(void)
4a6908d3
AS
3583{
3584 int result = 0;
3585 Flow f;
3586 int r = 0;
3587
3588 const char *request1_str = "EHLO boo.com";
3589 /* EHLO boo.com<CR> */
3590 uint8_t request1_1[] = {
3591 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3592 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
3593 };
3594 int32_t request1_1_len = sizeof(request1_1);
3595
3596 /* <LF> */
3597 uint8_t request1_2[] = {
3598 0x0a
3599 };
3600 int32_t request1_2_len = sizeof(request1_2);
3601
3602 /* EHLO boo.com<CR><LF> */
3603 uint8_t request2[] = {
3604 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3605 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3606 };
3607 int32_t request2_len = sizeof(request2);
3608
3609 TcpSession ssn;
8dbf7a0d 3610 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
4a6908d3
AS
3611
3612 memset(&f, 0, sizeof(f));
3613 memset(&ssn, 0, sizeof(ssn));
3614
3615 FLOW_INITIALIZE(&f);
3616 f.protoctx = (void *)&ssn;
429c6388 3617 f.proto = IPPROTO_TCP;
4a6908d3
AS
3618
3619 StreamTcpInitConfig(TRUE);
e43ce0a9 3620 SMTPTestInitConfig();
4a6908d3 3621
6530c3d0 3622 FLOWLOCK_WRLOCK(&f);
675fa564
GL
3623 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3624 STREAM_TOSERVER, request1_1, request1_1_len);
4a6908d3
AS
3625 if (r != 0) {
3626 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 3627 FLOWLOCK_UNLOCK(&f);
4a6908d3
AS
3628 goto end;
3629 }
6530c3d0 3630 FLOWLOCK_UNLOCK(&f);
bf24272c 3631 SMTPState *smtp_state = f.alstate;
4a6908d3
AS
3632 if (smtp_state == NULL) {
3633 printf("no smtp state: ");
3634 goto end;
3635 }
3636 if (smtp_state->current_line != NULL ||
3637 smtp_state->current_line_len != 0 ||
3638 smtp_state->ts_current_line_db != 1 ||
3639 smtp_state->ts_db == NULL ||
3640 smtp_state->ts_db_len != request1_1_len ||
3641 memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) {
3642 printf("smtp parser in inconsistent state\n");
3643 goto end;
3644 }
3645
6530c3d0 3646 FLOWLOCK_WRLOCK(&f);
675fa564
GL
3647 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3648 STREAM_TOSERVER, request1_2, request1_2_len);
4a6908d3
AS
3649 if (r != 0) {
3650 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 3651 FLOWLOCK_UNLOCK(&f);
4a6908d3
AS
3652 goto end;
3653 }
6530c3d0 3654 FLOWLOCK_UNLOCK(&f);
4a6908d3
AS
3655 if (smtp_state->ts_current_line_db != 1 ||
3656 smtp_state->ts_db == NULL ||
3657 smtp_state->ts_db_len != (int32_t)strlen(request1_str) ||
3658 memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 ||
3659 smtp_state->current_line != smtp_state->ts_db ||
3660 smtp_state->current_line_len != smtp_state->ts_db_len) {
3661 printf("smtp parser in inconsistent state\n");
3662 goto end;
3663 }
3664
6530c3d0 3665 FLOWLOCK_WRLOCK(&f);
675fa564
GL
3666 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3667 STREAM_TOSERVER, request2, request2_len);
4a6908d3
AS
3668 if (r != 0) {
3669 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 3670 FLOWLOCK_UNLOCK(&f);
4a6908d3
AS
3671 goto end;
3672 }
6530c3d0 3673 FLOWLOCK_UNLOCK(&f);
4a6908d3
AS
3674 if (smtp_state->ts_current_line_db != 0 ||
3675 smtp_state->ts_db != NULL ||
3676 smtp_state->ts_db_len != 0 ||
3677 smtp_state->current_line == NULL ||
3678 smtp_state->current_line_len != (int32_t)strlen(request1_str) ||
3679 memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) {
3680 printf("smtp parser in inconsistent state\n");
3681 goto end;
3682 }
3683
3684 result = 1;
3685end:
429c6388 3686 if (alp_tctx != NULL)
fdefb65b 3687 AppLayerParserThreadCtxFree(alp_tctx);
4a6908d3
AS
3688 StreamTcpFreeConfig(TRUE);
3689 FLOW_DESTROY(&f);
3690 return result;
3691}
3692
3693/*
3694 * \test Test retrieving lines when frag'ed.
3695 */
e43ce0a9 3696static int SMTPParserTest08(void)
4a6908d3
AS
3697{
3698 int result = 0;
3699 Flow f;
3700 int r = 0;
3701
3702 const char *request1_str = "EHLO boo.com";
3703 /* EHLO boo.com */
3704 uint8_t request1_1[] = {
3705 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3706 0x2e, 0x63, 0x6f, 0x6d,
3707 };
3708 int32_t request1_1_len = sizeof(request1_1);
3709
3710 /* <CR><LF> */
3711 uint8_t request1_2[] = {
3712 0x0d, 0x0a
3713 };
3714 int32_t request1_2_len = sizeof(request1_2);
3715
3716 /* EHLO boo.com<CR><LF> */
3717 uint8_t request2[] = {
3718 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3719 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3720 };
3721 int32_t request2_len = sizeof(request2);
3722
3723 TcpSession ssn;
8dbf7a0d 3724 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
4a6908d3
AS
3725
3726 memset(&f, 0, sizeof(f));
3727 memset(&ssn, 0, sizeof(ssn));
3728
3729 FLOW_INITIALIZE(&f);
3730 f.protoctx = (void *)&ssn;
429c6388 3731 f.proto = IPPROTO_TCP;
4a6908d3
AS
3732
3733 StreamTcpInitConfig(TRUE);
e43ce0a9 3734 SMTPTestInitConfig();
4a6908d3 3735
6530c3d0 3736 FLOWLOCK_WRLOCK(&f);
675fa564
GL
3737 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3738 STREAM_TOSERVER, request1_1, request1_1_len);
4a6908d3
AS
3739 if (r != 0) {
3740 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 3741 FLOWLOCK_UNLOCK(&f);
4a6908d3
AS
3742 goto end;
3743 }
6530c3d0 3744 FLOWLOCK_UNLOCK(&f);
bf24272c 3745 SMTPState *smtp_state = f.alstate;
4a6908d3
AS
3746 if (smtp_state == NULL) {
3747 printf("no smtp state: ");
3748 goto end;
3749 }
3750 if (smtp_state->current_line != NULL ||
3751 smtp_state->current_line_len != 0 ||
3752 smtp_state->ts_current_line_db != 1 ||
3753 smtp_state->ts_db == NULL ||
3754 smtp_state->ts_db_len != request1_1_len ||
3755 memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) {
3756 printf("smtp parser in inconsistent state\n");
3757 goto end;
3758 }
3759
6530c3d0 3760 FLOWLOCK_WRLOCK(&f);
675fa564
GL
3761 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3762 STREAM_TOSERVER, request1_2, request1_2_len);
4a6908d3
AS
3763 if (r != 0) {
3764 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 3765 FLOWLOCK_UNLOCK(&f);
4a6908d3
AS
3766 goto end;
3767 }
6530c3d0 3768 FLOWLOCK_UNLOCK(&f);
4a6908d3
AS
3769 if (smtp_state->ts_current_line_db != 1 ||
3770 smtp_state->ts_db == NULL ||
3771 smtp_state->ts_db_len != (int32_t)strlen(request1_str) ||
3772 memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 ||
3773 smtp_state->current_line != smtp_state->ts_db ||
3774 smtp_state->current_line_len != smtp_state->ts_db_len) {
3775 printf("smtp parser in inconsistent state\n");
3776 goto end;
3777 }
3778
6530c3d0 3779 FLOWLOCK_WRLOCK(&f);
675fa564
GL
3780 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3781 STREAM_TOSERVER, request2, request2_len);
4a6908d3
AS
3782 if (r != 0) {
3783 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 3784 FLOWLOCK_UNLOCK(&f);
4a6908d3
AS
3785 goto end;
3786 }
6530c3d0 3787 FLOWLOCK_UNLOCK(&f);
4a6908d3
AS
3788 if (smtp_state->ts_current_line_db != 0 ||
3789 smtp_state->ts_db != NULL ||
3790 smtp_state->ts_db_len != 0 ||
3791 smtp_state->current_line == NULL ||
3792 smtp_state->current_line_len != (int32_t)strlen(request1_str) ||
3793 memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) {
3794 printf("smtp parser in inconsistent state\n");
3795 goto end;
3796 }
3797
3798 result = 1;
3799end:
429c6388 3800 if (alp_tctx != NULL)
fdefb65b 3801 AppLayerParserThreadCtxFree(alp_tctx);
4a6908d3
AS
3802 StreamTcpFreeConfig(TRUE);
3803 FLOW_DESTROY(&f);
3804 return result;
3805}
3806
3807/*
3808 * \test Test retrieving lines when frag'ed.
3809 */
e43ce0a9 3810static int SMTPParserTest09(void)
4a6908d3
AS
3811{
3812 int result = 0;
3813 Flow f;
3814 int r = 0;
3815
3816 const char *request1_str = "EHLO boo.com";
3817 /* EHLO boo. */
3818 uint8_t request1_1[] = {
3819 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3820 0x2e,
3821 };
3822 int32_t request1_1_len = sizeof(request1_1);
3823
3824 /* com<CR><LF> */
3825 uint8_t request1_2[] = {
3826 0x63, 0x6f, 0x6d, 0x0d, 0x0a
3827 };
3828 int32_t request1_2_len = sizeof(request1_2);
3829
3830 /* EHLO boo.com<CR><LF> */
3831 uint8_t request2[] = {
3832 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3833 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3834 };
3835 int32_t request2_len = sizeof(request2);
3836
3837 TcpSession ssn;
8dbf7a0d 3838 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
4a6908d3
AS
3839
3840 memset(&f, 0, sizeof(f));
3841 memset(&ssn, 0, sizeof(ssn));
3842
3843 FLOW_INITIALIZE(&f);
3844 f.protoctx = (void *)&ssn;
429c6388 3845 f.proto = IPPROTO_TCP;
4a6908d3
AS
3846
3847 StreamTcpInitConfig(TRUE);
e43ce0a9 3848 SMTPTestInitConfig();
4a6908d3 3849
6530c3d0 3850 FLOWLOCK_WRLOCK(&f);
675fa564
GL
3851 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3852 STREAM_TOSERVER, request1_1, request1_1_len);
4a6908d3
AS
3853 if (r != 0) {
3854 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 3855 FLOWLOCK_UNLOCK(&f);
4a6908d3
AS
3856 goto end;
3857 }
6530c3d0 3858 FLOWLOCK_UNLOCK(&f);
bf24272c 3859 SMTPState *smtp_state = f.alstate;
4a6908d3
AS
3860 if (smtp_state == NULL) {
3861 printf("no smtp state: ");
3862 goto end;
3863 }
3864 if (smtp_state->current_line != NULL ||
3865 smtp_state->current_line_len != 0 ||
3866 smtp_state->ts_current_line_db != 1 ||
3867 smtp_state->ts_db == NULL ||
3868 smtp_state->ts_db_len != request1_1_len ||
3869 memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) {
3870 printf("smtp parser in inconsistent state\n");
3871 goto end;
3872 }
3873
6530c3d0 3874 FLOWLOCK_WRLOCK(&f);
675fa564
GL
3875 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3876 STREAM_TOSERVER, request1_2, request1_2_len);
4a6908d3
AS
3877 if (r != 0) {
3878 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 3879 FLOWLOCK_UNLOCK(&f);
4a6908d3
AS
3880 goto end;
3881 }
6530c3d0 3882 FLOWLOCK_UNLOCK(&f);
4a6908d3
AS
3883 if (smtp_state->ts_current_line_db != 1 ||
3884 smtp_state->ts_db == NULL ||
3885 smtp_state->ts_db_len != (int32_t)strlen(request1_str) ||
3886 memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 ||
3887 smtp_state->current_line != smtp_state->ts_db ||
3888 smtp_state->current_line_len != smtp_state->ts_db_len) {
3889 printf("smtp parser in inconsistent state\n");
3890 goto end;
3891 }
3892
6530c3d0 3893 FLOWLOCK_WRLOCK(&f);
675fa564
GL
3894 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3895 STREAM_TOSERVER, request2, request2_len);
4a6908d3
AS
3896 if (r != 0) {
3897 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 3898 FLOWLOCK_UNLOCK(&f);
4a6908d3
AS
3899 goto end;
3900 }
6530c3d0 3901 FLOWLOCK_UNLOCK(&f);
4a6908d3
AS
3902 if (smtp_state->ts_current_line_db != 0 ||
3903 smtp_state->ts_db != NULL ||
3904 smtp_state->ts_db_len != 0 ||
3905 smtp_state->current_line == NULL ||
3906 smtp_state->current_line_len != (int32_t)strlen(request1_str) ||
3907 memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) {
3908 printf("smtp parser in inconsistent state\n");
3909 goto end;
3910 }
3911
3912 result = 1;
3913end:
429c6388 3914 if (alp_tctx != NULL)
fdefb65b 3915 AppLayerParserThreadCtxFree(alp_tctx);
4a6908d3
AS
3916 StreamTcpFreeConfig(TRUE);
3917 FLOW_DESTROY(&f);
3918 return result;
3919}
3920
3921/*
3922 * \test Test retrieving lines when frag'ed.
3923 */
e43ce0a9 3924static int SMTPParserTest10(void)
4a6908d3
AS
3925{
3926 int result = 0;
3927 Flow f;
3928 int r = 0;
3929
3930 const char *request1_str = "";
3931 /* EHLO boo. */
3932 uint8_t request1_1[] = {
3933 0x0d,
3934 };
3935 int32_t request1_1_len = sizeof(request1_1);
3936
3937 /* com<CR><LF> */
3938 uint8_t request1_2[] = {
3939 0x0a,
3940 };
3941 int32_t request1_2_len = sizeof(request1_2);
3942
3943 const char *request2_str = "EHLO boo.com";
3944 /* EHLO boo.com<CR><LF> */
3945 uint8_t request2[] = {
3946 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3947 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3948 };
3949 int32_t request2_len = sizeof(request2);
3950
3951 TcpSession ssn;
8dbf7a0d 3952 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
4a6908d3
AS
3953
3954 memset(&f, 0, sizeof(f));
3955 memset(&ssn, 0, sizeof(ssn));
3956
3957 FLOW_INITIALIZE(&f);
3958 f.protoctx = (void *)&ssn;
429c6388 3959 f.proto = IPPROTO_TCP;
4a6908d3
AS
3960
3961 StreamTcpInitConfig(TRUE);
e43ce0a9 3962 SMTPTestInitConfig();
4a6908d3 3963
6530c3d0 3964 FLOWLOCK_WRLOCK(&f);
675fa564
GL
3965 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3966 STREAM_TOSERVER, request1_1, request1_1_len);
4a6908d3
AS
3967 if (r != 0) {
3968 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 3969 FLOWLOCK_UNLOCK(&f);
4a6908d3
AS
3970 goto end;
3971 }
6530c3d0 3972 FLOWLOCK_UNLOCK(&f);
bf24272c 3973 SMTPState *smtp_state = f.alstate;
4a6908d3
AS
3974 if (smtp_state == NULL) {
3975 printf("no smtp state: ");
3976 goto end;
3977 }
3978 if (smtp_state->current_line != NULL ||
3979 smtp_state->current_line_len != 0 ||
3980 smtp_state->ts_current_line_db != 1 ||
3981 smtp_state->ts_db == NULL ||
3982 smtp_state->ts_db_len != request1_1_len ||
3983 memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) {
3984 printf("smtp parser in inconsistent state\n");
3985 goto end;
3986 }
3987
6530c3d0 3988 FLOWLOCK_WRLOCK(&f);
675fa564
GL
3989 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3990 STREAM_TOSERVER, request1_2, request1_2_len);
4a6908d3
AS
3991 if (r != 0) {
3992 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 3993 FLOWLOCK_UNLOCK(&f);
4a6908d3
AS
3994 goto end;
3995 }
6530c3d0 3996 FLOWLOCK_UNLOCK(&f);
4a6908d3
AS
3997 if (smtp_state->ts_current_line_db != 1 ||
3998 smtp_state->ts_db == NULL ||
3999 smtp_state->ts_db_len != (int32_t)strlen(request1_str) ||
4000 memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 ||
4001 smtp_state->current_line != smtp_state->ts_db ||
4002 smtp_state->current_line_len != smtp_state->ts_db_len) {
4003 printf("smtp parser in inconsistent state\n");
4004 goto end;
4005 }
4006
6530c3d0 4007 FLOWLOCK_WRLOCK(&f);
675fa564
GL
4008 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4009 STREAM_TOSERVER, request2, request2_len);
4a6908d3
AS
4010 if (r != 0) {
4011 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 4012 FLOWLOCK_UNLOCK(&f);
4a6908d3
AS
4013 goto end;
4014 }
6530c3d0 4015 FLOWLOCK_UNLOCK(&f);
4a6908d3
AS
4016 if (smtp_state->ts_current_line_db != 0 ||
4017 smtp_state->ts_db != NULL ||
4018 smtp_state->ts_db_len != 0 ||
4019 smtp_state->current_line == NULL ||
4020 smtp_state->current_line_len != (int32_t)strlen(request2_str) ||
4021 memcmp(smtp_state->current_line, request2_str, strlen(request2_str)) != 0) {
4022 printf("smtp parser in inconsistent state\n");
4023 goto end;
4024 }
4025
4026 result = 1;
4027end:
429c6388 4028 if (alp_tctx != NULL)
fdefb65b 4029 AppLayerParserThreadCtxFree(alp_tctx);
4a6908d3
AS
4030 StreamTcpFreeConfig(TRUE);
4031 FLOW_DESTROY(&f);
4032 return result;
4033}
4034
4035/*
4036 * \test Test retrieving lines when frag'ed.
4037 */
e43ce0a9 4038static int SMTPParserTest11(void)
4a6908d3
AS
4039{
4040 int result = 0;
4041 Flow f;
4042 int r = 0;
4043
4044 const char *request1_str = "";
4045 /* EHLO boo. */
4046 uint8_t request1[] = {
4047 0x0a,
4048 };
4049 int32_t request1_len = sizeof(request1);
4050
4051 const char *request2_str = "EHLO boo.com";
4052 /* EHLO boo.com<CR><LF> */
4053 uint8_t request2[] = {
4054 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
4055 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
4056 };
4057 int32_t request2_len = sizeof(request2);
4058
4059 TcpSession ssn;
8dbf7a0d 4060 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
4a6908d3
AS
4061
4062 memset(&f, 0, sizeof(f));
4063 memset(&ssn, 0, sizeof(ssn));
4064
4065 FLOW_INITIALIZE(&f);
4066 f.protoctx = (void *)&ssn;
429c6388 4067 f.proto = IPPROTO_TCP;
4a6908d3
AS
4068
4069 StreamTcpInitConfig(TRUE);
e43ce0a9 4070 SMTPTestInitConfig();
4a6908d3 4071
6530c3d0 4072 FLOWLOCK_WRLOCK(&f);
675fa564
GL
4073 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4074 STREAM_TOSERVER, request1, request1_len);
4a6908d3
AS
4075 if (r != 0) {
4076 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 4077 FLOWLOCK_UNLOCK(&f);
4a6908d3
AS
4078 goto end;
4079 }
6530c3d0 4080 FLOWLOCK_UNLOCK(&f);
bf24272c 4081 SMTPState *smtp_state = f.alstate;
4a6908d3
AS
4082 if (smtp_state == NULL) {
4083 printf("no smtp state: ");
4084 goto end;
4085 }
4086 if (smtp_state->current_line == NULL ||
4087 smtp_state->current_line_len != 0 ||
4088 smtp_state->ts_current_line_db == 1 ||
4089 smtp_state->ts_db != NULL ||
4090 smtp_state->ts_db_len != 0 ||
4091 memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) {
4092 printf("smtp parser in inconsistent state\n");
4093 goto end;
4094 }
4095
6530c3d0 4096 FLOWLOCK_WRLOCK(&f);
675fa564
GL
4097 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4098 STREAM_TOSERVER, request2, request2_len);
4a6908d3
AS
4099 if (r != 0) {
4100 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 4101 FLOWLOCK_UNLOCK(&f);
4a6908d3
AS
4102 goto end;
4103 }
6530c3d0 4104 FLOWLOCK_UNLOCK(&f);
4a6908d3
AS
4105 if (smtp_state->ts_current_line_db != 0 ||
4106 smtp_state->ts_db != NULL ||
4107 smtp_state->ts_db_len != 0 ||
4108 smtp_state->current_line == NULL ||
4109 smtp_state->current_line_len != (int32_t)strlen(request2_str) ||
4110 memcmp(smtp_state->current_line, request2_str, strlen(request2_str)) != 0) {
4111 printf("smtp parser in inconsistent state\n");
4112 goto end;
4113 }
4114
4115 result = 1;
4116end:
429c6388 4117 if (alp_tctx != NULL)
fdefb65b 4118 AppLayerParserThreadCtxFree(alp_tctx);
4a6908d3
AS
4119 StreamTcpFreeConfig(TRUE);
4120 FLOW_DESTROY(&f);
4121 return result;
4122}
4123
e43ce0a9 4124static int SMTPParserTest12(void)
5311cd48
AS
4125{
4126 int result = 0;
4127 Signature *s = NULL;
4128 ThreadVars th_v;
4129 Packet *p = NULL;
4130 Flow f;
4131 TcpSession ssn;
4132 DetectEngineThreadCtx *det_ctx = NULL;
4133 DetectEngineCtx *de_ctx = NULL;
4134 SMTPState *smtp_state = NULL;
4135 int r = 0;
4136
4137 /* EHLO boo.com<CR><LF> */
4138 uint8_t request1[] = {
4139 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
4140 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
4141 };
4142 int32_t request1_len = sizeof(request1);
4143
4144 /* 388<CR><LF>
4145 */
4146 uint8_t reply1[] = {
4147 0x31, 0x38, 0x38, 0x0d, 0x0a,
4148 };
4149 uint32_t reply1_len = sizeof(reply1);
4150
8dbf7a0d 4151 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
429c6388 4152
5311cd48
AS
4153 memset(&th_v, 0, sizeof(th_v));
4154 memset(&f, 0, sizeof(f));
4155 memset(&ssn, 0, sizeof(ssn));
4156
4157 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
4158
4159 FLOW_INITIALIZE(&f);
4160 f.protoctx = (void *)&ssn;
429c6388 4161 f.proto = IPPROTO_TCP;
5311cd48
AS
4162 p->flow = &f;
4163 p->flowflags |= FLOW_PKT_TOSERVER;
4164 p->flowflags |= FLOW_PKT_ESTABLISHED;
4165 p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
4166 f.alproto = ALPROTO_SMTP;
4167
4168 StreamTcpInitConfig(TRUE);
e43ce0a9 4169 SMTPTestInitConfig();
5311cd48
AS
4170
4171 de_ctx = DetectEngineCtxInit();
4172 if (de_ctx == NULL)
4173 goto end;
4174
4175 de_ctx->flags |= DE_QUIET;
4176
4177 s = DetectEngineAppendSig(de_ctx,"alert tcp any any -> any any "
4178 "(msg:\"SMTP event handling\"; "
7fa22e84 4179 "app-layer-event: smtp.invalid_reply; "
5311cd48
AS
4180 "sid:1;)");
4181 if (s == NULL)
4182 goto end;
4183
4184 SigGroupBuild(de_ctx);
4185 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
4186
6530c3d0 4187 FLOWLOCK_WRLOCK(&f);
675fa564
GL
4188 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4189 STREAM_TOSERVER | STREAM_START, request1,
4190 request1_len);
5311cd48
AS
4191 if (r != 0) {
4192 printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
6530c3d0 4193 FLOWLOCK_UNLOCK(&f);
5311cd48
AS
4194 goto end;
4195 }
6530c3d0 4196 FLOWLOCK_UNLOCK(&f);
5311cd48
AS
4197
4198 smtp_state = f.alstate;
4199 if (smtp_state == NULL) {
4200 printf("no smtp state: ");
4201 goto end;
4202 }
4203
4204 /* do detect */
4205 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4206
4207 if (PacketAlertCheck(p, 1)) {
4208 printf("sid 1 matched. It shouldn't match: ");
4209 goto end;
4210 }
4211
6530c3d0 4212 FLOWLOCK_WRLOCK(&f);
675fa564
GL
4213 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4214 STREAM_TOCLIENT | STREAM_TOCLIENT, reply1,
4215 reply1_len);
5311cd48
AS
4216 if (r == 0) {
4217 printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
6530c3d0 4218 FLOWLOCK_UNLOCK(&f);
5311cd48
AS
4219 goto end;
4220 }
6530c3d0 4221 FLOWLOCK_UNLOCK(&f);
5311cd48
AS
4222
4223 /* do detect */
4224 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4225
4226 if (!PacketAlertCheck(p, 1)) {
4227 printf("sid 1 didn't match. Should have matched: ");
4228 goto end;
4229 }
4230
4231 result = 1;
4232
4233end:
4234 SigGroupCleanup(de_ctx);
4235 SigCleanSignatures(de_ctx);
4236
4237 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
4238 DetectEngineCtxFree(de_ctx);
4239
429c6388 4240 if (alp_tctx != NULL)
fdefb65b 4241 AppLayerParserThreadCtxFree(alp_tctx);
5311cd48 4242 StreamTcpFreeConfig(TRUE);
5311cd48
AS
4243 FLOW_DESTROY(&f);
4244 UTHFreePackets(&p, 1);
4245 return result;
4246}
4247
e43ce0a9 4248static int SMTPParserTest13(void)
5311cd48
AS
4249{
4250 int result = 0;
4251 Signature *s = NULL;
4252 ThreadVars th_v;
4253 Packet *p = NULL;
4254 Flow f;
4255 TcpSession ssn;
4256 DetectEngineThreadCtx *det_ctx = NULL;
4257 DetectEngineCtx *de_ctx = NULL;
4258 SMTPState *smtp_state = NULL;
4259 int r = 0;
4260
4261 /* EHLO boo.com<CR><LF> */
4262 uint8_t request1[] = {
4263 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
4264 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
4265 };
4266 int32_t request1_len = sizeof(request1);
4267
4268 /* 250<CR><LF>
4269 */
4270 uint8_t reply1[] = {
4271 0x32, 0x35, 0x30, 0x0d, 0x0a,
4272 };
4273 uint32_t reply1_len = sizeof(reply1);
4274
4275 /* MAIL FROM:pbsf@asdfs.com<CR><LF>
4276 * RCPT TO:pbsf@asdfs.com<CR><LF>
4277 * DATA<CR><LF>
4278 * STARTTLS<CR><LF>
4279 */
4280 uint8_t request2[] = {
4281 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
4282 0x4d, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
4283 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
4284 0x0d, 0x0a, 0x52, 0x43, 0x50, 0x54, 0x20, 0x54,
4285 0x4f, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
4286 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
4287 0x0d, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a,
4288 0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
4289 0x0d, 0x0a
4290 };
4291 uint32_t request2_len = sizeof(request2);
4292
8dbf7a0d 4293 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
429c6388 4294
5311cd48
AS
4295 memset(&th_v, 0, sizeof(th_v));
4296 memset(&f, 0, sizeof(f));
4297 memset(&ssn, 0, sizeof(ssn));
4298
4299 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
4300
4301 FLOW_INITIALIZE(&f);
4302 f.protoctx = (void *)&ssn;
429c6388 4303 f.proto = IPPROTO_TCP;
5311cd48
AS
4304 p->flow = &f;
4305 p->flowflags |= FLOW_PKT_TOSERVER;
4306 p->flowflags |= FLOW_PKT_ESTABLISHED;
4307 p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
4308 f.alproto = ALPROTO_SMTP;
4309
4310 StreamTcpInitConfig(TRUE);
e43ce0a9 4311 SMTPTestInitConfig();
5311cd48
AS
4312
4313 de_ctx = DetectEngineCtxInit();
4314 if (de_ctx == NULL)
4315 goto end;
4316
4317 de_ctx->flags |= DE_QUIET;
4318
4319 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
4320 "(msg:\"SMTP event handling\"; "
7fa22e84 4321 "app-layer-event: "
5311cd48
AS
4322 "smtp.invalid_pipelined_sequence; "
4323 "sid:1;)");
4324 if (s == NULL)
4325 goto end;
4326
4327 SigGroupBuild(de_ctx);
4328 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
4329
6530c3d0 4330 FLOWLOCK_WRLOCK(&f);
675fa564
GL
4331 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4332 STREAM_TOSERVER | STREAM_START, request1,
4333 request1_len);
5311cd48
AS
4334 if (r != 0) {
4335 printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
6530c3d0 4336 FLOWLOCK_UNLOCK(&f);
5311cd48
AS
4337 goto end;
4338 }
6530c3d0 4339 FLOWLOCK_UNLOCK(&f);
5311cd48
AS
4340
4341 smtp_state = f.alstate;
4342 if (smtp_state == NULL) {
4343 printf("no smtp state: ");
4344 goto end;
4345 }
4346
4347 /* do detect */
4348 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4349
4350 if (PacketAlertCheck(p, 1)) {
4351 printf("sid 1 matched. It shouldn't match: ");
4352 goto end;
4353 }
4354
6530c3d0 4355 FLOWLOCK_WRLOCK(&f);
675fa564
GL
4356 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4357 STREAM_TOCLIENT, reply1, reply1_len);
5311cd48
AS
4358 if (r != 0) {
4359 printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
6530c3d0 4360 FLOWLOCK_UNLOCK(&f);
5311cd48
AS
4361 goto end;
4362 }
6530c3d0 4363 FLOWLOCK_UNLOCK(&f);
5311cd48
AS
4364
4365 /* do detect */
4366 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4367
4368 if (PacketAlertCheck(p, 1)) {
4369 printf("sid 1 matched. It shouldn't match: ");
4370 goto end;
4371 }
4372
6530c3d0 4373 FLOWLOCK_WRLOCK(&f);
675fa564
GL
4374 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4375 STREAM_TOSERVER, request2, request2_len);
5311cd48
AS
4376 if (r != 0) {
4377 printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
6530c3d0 4378 FLOWLOCK_UNLOCK(&f);
5311cd48
AS
4379 goto end;
4380 }
6530c3d0 4381 FLOWLOCK_UNLOCK(&f);
5311cd48
AS
4382
4383 /* do detect */
4384 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4385
4386 if (!PacketAlertCheck(p, 1)) {
4387 printf("sid 1 didn't match. Should have matched: ");
4388 goto end;
4389 }
4390
4391 result = 1;
4392
4393end:
4394 SigGroupCleanup(de_ctx);
4395 SigCleanSignatures(de_ctx);
4396
4397 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
4398 DetectEngineCtxFree(de_ctx);
4399
429c6388 4400 if (alp_tctx != NULL)
fdefb65b 4401 AppLayerParserThreadCtxFree(alp_tctx);
5311cd48 4402 StreamTcpFreeConfig(TRUE);
5311cd48
AS
4403 FLOW_DESTROY(&f);
4404 UTHFreePackets(&p, 1);
4405 return result;
4406}
4407
c2dc6867
DA
4408/**
4409 * \test Test DATA command w/MIME message.
4410 */
e43ce0a9 4411static int SMTPParserTest14(void)
c2dc6867
DA
4412{
4413 int result = 0;
4414 Flow f;
4415 int r = 0;
4416
4417 /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
6467a5d5 4418 static uint8_t welcome_reply[] = {
c2dc6867
DA
4419 0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
4420 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
4421 0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
4422 0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
4423 0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
4424 0x0d, 0x0a
4425 };
6467a5d5 4426 static uint32_t welcome_reply_len = sizeof(welcome_reply);
c2dc6867
DA
4427
4428 /* EHLO boo.com<CR><LF> */
6467a5d5 4429 static uint8_t request1[] = {
c2dc6867
DA
4430 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
4431 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
4432 };
6467a5d5 4433 static uint32_t request1_len = sizeof(request1);
c2dc6867
DA
4434 /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
4435 * 250-SIZE 35882577<CR><LF>
4436 * 250-8BITMIME<CR><LF>
4437 * 250-STARTTLS<CR><LF>
4438 * 250 ENHANCEDSTATUSCODES<CR><LF>
4439 */
6467a5d5 4440 static uint8_t reply1[] = {
c2dc6867
DA
4441 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
4442 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
4443 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
4444 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
4445 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
4446 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
4447 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
4448 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
4449 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
4450 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
4451 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
4452 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
4453 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
4454 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
4455 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
4456 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
4457 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
4458 };
6467a5d5 4459 static uint32_t reply1_len = sizeof(reply1);
c2dc6867
DA
4460
4461 /* MAIL FROM:asdff@asdf.com<CR><LF> */
6467a5d5 4462 static uint8_t request2[] = {
c2dc6867
DA
4463 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
4464 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
4465 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
4466 0x0d, 0x0a
4467 };
6467a5d5 4468 static uint32_t request2_len = sizeof(request2);
c2dc6867 4469 /* 250 2.1.0 Ok<CR><LF> */
6467a5d5 4470 static uint8_t reply2[] = {
c2dc6867
DA
4471 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
4472 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
4473 };
6467a5d5 4474 static uint32_t reply2_len = sizeof(reply2);
c2dc6867
DA
4475
4476 /* RCPT TO:bimbs@gmail.com<CR><LF> */
6467a5d5 4477 static uint8_t request3[] = {
c2dc6867
DA
4478 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
4479 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
4480 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
4481 0x0a
4482 };
6467a5d5 4483 static uint32_t request3_len = sizeof(request3);
c2dc6867 4484 /* 250 2.1.5 Ok<CR><LF> */
6467a5d5 4485 static uint8_t reply3[] = {
c2dc6867
DA
4486 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
4487 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
4488 };
6467a5d5 4489 static uint32_t reply3_len = sizeof(reply3);
c2dc6867
DA
4490
4491 /* DATA<CR><LF> */
6467a5d5 4492 static uint8_t request4[] = {
c2dc6867
DA
4493 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
4494 };
6467a5d5 4495 static uint32_t request4_len = sizeof(request4);
c2dc6867 4496 /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
6467a5d5 4497 static uint8_t reply4[] = {
c2dc6867
DA
4498 0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
4499 0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
4500 0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
4501 0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
4502 0x4c, 0x46, 0x3e, 0x0d, 0x0a
4503 };
6467a5d5 4504 static uint32_t reply4_len = sizeof(reply4);
c2dc6867
DA
4505
4506 /* MIME_MSG */
6467a5d5
TD
4507 static uint64_t filesize = 133;
4508 static uint8_t request4_msg[] = {
c2dc6867
DA
4509 0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72,
4510 0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E,
4511 0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
4512 0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A,
4513 0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61,
4514 0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74,
4515 0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61,
4516 0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
4517 0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73,
4518 0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F,
4519 0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61,
4520 0x73, 0x65, 0x36, 0x34, 0x0D, 0x0A, 0x43, 0x6F,
4521 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x44, 0x69,
4522 0x73, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F,
4523 0x6E, 0x3A, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63,
4524 0x68, 0x6D, 0x65, 0x6E, 0x74, 0x3B, 0x20, 0x66,
4525 0x69, 0x6C, 0x65, 0x6E, 0x61, 0x6D, 0x65, 0x3D,
4526 0x22, 0x74, 0x65, 0x73, 0x74, 0x2E, 0x65, 0x78,
4527 0x65, 0x22, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x54,
4528 0x56, 0x6F, 0x41, 0x41, 0x46, 0x42, 0x46, 0x41,
4529 0x41, 0x42, 0x4D, 0x41, 0x51, 0x45, 0x41, 0x61,
4530 0x69, 0x70, 0x59, 0x77, 0x77, 0x41, 0x41, 0x41,
4531 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
4532 0x41, 0x41, 0x44, 0x41, 0x51, 0x73, 0x42, 0x43,
4533 0x41, 0x41, 0x42, 0x41, 0x41, 0x43, 0x41, 0x41,
4534 0x41, 0x41, 0x41, 0x41, 0x48, 0x6B, 0x41, 0x41,
4535 0x41, 0x41, 0x4D, 0x41, 0x41, 0x41, 0x41, 0x65,
4536 0x51, 0x41, 0x41, 0x41, 0x41, 0x77, 0x41, 0x41,
4537 0x41, 0x41, 0x41, 0x41, 0x45, 0x41, 0x41, 0x42,
4538 0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
4539 0x41, 0x42, 0x30, 0x41, 0x41, 0x41, 0x41, 0x49,
4540 0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
4541 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
4542 0x41, 0x45, 0x41, 0x41, 0x49, 0x67, 0x41, 0x41,
4543 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4544 0x67, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4545 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4546 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4547 0x41, 0x42, 0x63, 0x58, 0x44, 0x59, 0x32, 0x4C,
4548 0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C,
4549 0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F,
4550 0x41, 0x3D, 0x3D, 0x0D,0x0A };
6467a5d5 4551 static uint32_t request4_msg_len = sizeof(request4_msg);
c2dc6867
DA
4552
4553 /* DATA COMPLETED */
6467a5d5 4554 static uint8_t request4_end[] = {
c2dc6867
DA
4555 0x0d, 0x0a, 0x2e, 0x0d, 0x0a
4556 };
6467a5d5 4557 static uint32_t request4_end_len = sizeof(request4_end);
c2dc6867 4558 /* 250 2.0.0 Ok: queued as 6A1AF20BF2<CR><LF> */
6467a5d5 4559 static uint8_t reply4_end[] = {
c2dc6867
DA
4560 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
4561 0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
4562 0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
4563 0x36, 0x41, 0x31, 0x41, 0x46, 0x32, 0x30, 0x42,
4564 0x46, 0x32, 0x0d, 0x0a
4565 };
6467a5d5 4566 static uint32_t reply4_end_len = sizeof(reply4_end);
c2dc6867
DA
4567
4568 /* QUIT<CR><LF> */
6467a5d5 4569 static uint8_t request5[] = {
c2dc6867
DA
4570 0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
4571 };
6467a5d5 4572 static uint32_t request5_len = sizeof(request5);
c2dc6867 4573 /* 221 2.0.0 Bye<CR><LF> */
6467a5d5 4574 static uint8_t reply5[] = {
c2dc6867
DA
4575 0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
4576 0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
4577 };
6467a5d5 4578 static uint32_t reply5_len = sizeof(reply5);
c2dc6867
DA
4579
4580 TcpSession ssn;
260872cc 4581 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
c2dc6867
DA
4582
4583 memset(&f, 0, sizeof(f));
4584 memset(&ssn, 0, sizeof(ssn));
4585
4586 FLOW_INITIALIZE(&f);
4587 f.protoctx = (void *)&ssn;
260872cc 4588 f.proto = IPPROTO_TCP;
c2dc6867
DA
4589
4590 StreamTcpInitConfig(TRUE);
e43ce0a9 4591 SMTPTestInitConfig();
c2dc6867 4592
6530c3d0 4593 FLOWLOCK_WRLOCK(&f);
260872cc 4594 /* Welcome reply */
675fa564
GL
4595 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4596 STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
c2dc6867
DA
4597 if (r != 0) {
4598 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 4599 FLOWLOCK_UNLOCK(&f);
c2dc6867
DA
4600 goto end;
4601 }
6530c3d0 4602 FLOWLOCK_UNLOCK(&f);
c2dc6867
DA
4603 SMTPState *smtp_state = f.alstate;
4604 if (smtp_state == NULL) {
4605 printf("no smtp state: ");
4606 goto end;
4607 }
4608 if (smtp_state->input_len != 0 ||
260872cc 4609 smtp_state->cmds_cnt != 0 ||
c2dc6867 4610 smtp_state->cmds_idx != 0 ||
260872cc
EL
4611 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
4612 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4613 goto end;
4614 }
4615
6530c3d0 4616 FLOWLOCK_WRLOCK(&f);
675fa564
GL
4617 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4618 STREAM_TOSERVER, request1, request1_len);
c2dc6867
DA
4619 if (r != 0) {
4620 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 4621 FLOWLOCK_UNLOCK(&f);
c2dc6867
DA
4622 goto end;
4623 }
6530c3d0 4624 FLOWLOCK_UNLOCK(&f);
c2dc6867
DA
4625 if (smtp_state->input_len != 0 ||
4626 smtp_state->cmds_cnt != 1 ||
4627 smtp_state->cmds_idx != 0 ||
4628 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4629 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
260872cc 4630 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4631 goto end;
4632 }
4633
6530c3d0 4634 FLOWLOCK_WRLOCK(&f);
c2dc6867 4635 /* EHLO Reply */
675fa564
GL
4636 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4637 STREAM_TOCLIENT, reply1, reply1_len);
c2dc6867
DA
4638 if (r != 0) {
4639 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 4640 FLOWLOCK_UNLOCK(&f);
c2dc6867
DA
4641 goto end;
4642 }
534360fc
EL
4643
4644 if ((smtp_state->helo_len != 7) || strncmp("boo.com", (char *)smtp_state->helo, 7)) {
4645 printf("incorrect parsing of HELO field '%s' (%d)\n", smtp_state->helo, smtp_state->helo_len);
6530c3d0 4646 FLOWLOCK_UNLOCK(&f);
534360fc
EL
4647 goto end;
4648 }
4649
6530c3d0 4650 FLOWLOCK_UNLOCK(&f);
c2dc6867
DA
4651 if (smtp_state->input_len != 0 ||
4652 smtp_state->cmds_cnt != 0 ||
4653 smtp_state->cmds_idx != 0 ||
4654 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
260872cc 4655 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4656 goto end;
4657 }
4658
6530c3d0 4659 FLOWLOCK_WRLOCK(&f);
c2dc6867 4660 /* MAIL FROM Request */
675fa564
GL
4661 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4662 STREAM_TOSERVER, request2, request2_len);
c2dc6867
DA
4663 if (r != 0) {
4664 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 4665 FLOWLOCK_UNLOCK(&f);
c2dc6867
DA
4666 goto end;
4667 }
6530c3d0 4668 FLOWLOCK_UNLOCK(&f);
c2dc6867
DA
4669 if (smtp_state->input_len != 0 ||
4670 smtp_state->cmds_cnt != 1 ||
4671 smtp_state->cmds_idx != 0 ||
4672 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4673 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
260872cc 4674 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4675 goto end;
4676 }
4677
6530c3d0 4678 FLOWLOCK_WRLOCK(&f);
c2dc6867 4679 /* MAIL FROM Reply */
675fa564
GL
4680 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4681 STREAM_TOCLIENT, reply2, reply2_len);
c2dc6867
DA
4682 if (r != 0) {
4683 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 4684 FLOWLOCK_UNLOCK(&f);
c2dc6867
DA
4685 goto end;
4686 }
fbd6428f
EL
4687
4688 if ((smtp_state->curr_tx->mail_from_len != 14) ||
4689 strncmp("asdff@asdf.com", (char *)smtp_state->curr_tx->mail_from, 14)) {
4690 printf("incorrect parsing of MAIL FROM field '%s' (%d)\n",
4691 smtp_state->curr_tx->mail_from,
4692 smtp_state->curr_tx->mail_from_len);
6530c3d0 4693 FLOWLOCK_UNLOCK(&f);
fbd6428f
EL
4694 goto end;
4695 }
4696
6530c3d0 4697 FLOWLOCK_UNLOCK(&f);
c2dc6867
DA
4698 if (smtp_state->input_len != 0 ||
4699 smtp_state->cmds_cnt != 0 ||
4700 smtp_state->cmds_idx != 0 ||
4701 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
260872cc 4702 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4703 goto end;
4704 }
4705
6530c3d0 4706 FLOWLOCK_WRLOCK(&f);
c2dc6867 4707 /* RCPT TO Request */
675fa564
GL
4708 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4709 STREAM_TOSERVER, request3, request3_len);
c2dc6867
DA
4710 if (r != 0) {
4711 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 4712 FLOWLOCK_UNLOCK(&f);
c2dc6867
DA
4713 goto end;
4714 }
6530c3d0 4715 FLOWLOCK_UNLOCK(&f);
c2dc6867
DA
4716 if (smtp_state->input_len != 0 ||
4717 smtp_state->cmds_cnt != 1 ||
4718 smtp_state->cmds_idx != 0 ||
4719 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4720 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
260872cc 4721 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4722 goto end;
4723 }
4724
6530c3d0 4725 FLOWLOCK_WRLOCK(&f);
c2dc6867 4726 /* RCPT TO Reply */
675fa564
GL
4727 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4728 STREAM_TOCLIENT, reply3, reply3_len);
c2dc6867
DA
4729 if (r != 0) {
4730 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 4731 FLOWLOCK_UNLOCK(&f);
c2dc6867
DA
4732 goto end;
4733 }
6530c3d0 4734 FLOWLOCK_UNLOCK(&f);
c2dc6867
DA
4735 if (smtp_state->input_len != 0 ||
4736 smtp_state->cmds_cnt != 0 ||
4737 smtp_state->cmds_idx != 0 ||
4738 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
260872cc 4739 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4740 goto end;
4741 }
4742
4743 /* Enable mime decoding */
4744 smtp_config.decode_mime = 1;
4745 smtp_config.mime_config.decode_base64 = 1;
4746 smtp_config.mime_config.decode_quoted_printable = 1;
4747 MimeDecSetConfig(&smtp_config.mime_config);
4748
6530c3d0 4749 FLOWLOCK_WRLOCK(&f);
c2dc6867 4750 /* DATA request */
675fa564
GL
4751 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4752 STREAM_TOSERVER, request4, request4_len);
c2dc6867
DA
4753 if (r != 0) {
4754 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 4755 FLOWLOCK_UNLOCK(&f);
c2dc6867
DA
4756 goto end;
4757 }
6530c3d0 4758 FLOWLOCK_UNLOCK(&f);
c2dc6867
DA
4759
4760 if (smtp_state->input_len != 0 ||
4761 smtp_state->cmds_cnt != 1 ||
4762 smtp_state->cmds_idx != 0 ||
4763 smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
4764 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
260872cc 4765 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4766 goto end;
4767 }
4768
6530c3d0 4769 FLOWLOCK_WRLOCK(&f);
c2dc6867 4770 /* Data reply */
675fa564
GL
4771 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4772 STREAM_TOCLIENT, reply4, reply4_len);
c2dc6867
DA
4773 if (r != 0) {
4774 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 4775 FLOWLOCK_UNLOCK(&f);
c2dc6867
DA
4776 goto end;
4777 }
6530c3d0 4778 FLOWLOCK_UNLOCK(&f);
c2dc6867
DA
4779 if (smtp_state->input_len != 0 ||
4780 smtp_state->cmds_cnt != 0 ||
4781 smtp_state->cmds_idx != 0 ||
4782 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
4783 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
260872cc 4784 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4785 goto end;
4786 }
4787
6530c3d0 4788 FLOWLOCK_WRLOCK(&f);
c2dc6867 4789 /* DATA message */
675fa564
GL
4790 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4791 STREAM_TOSERVER, request4_msg, request4_msg_len);
c2dc6867
DA
4792 if (r != 0) {
4793 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 4794 FLOWLOCK_UNLOCK(&f);
c2dc6867
DA
4795 goto end;
4796 }
6530c3d0 4797 FLOWLOCK_UNLOCK(&f);
c2dc6867
DA
4798
4799 if (smtp_state->input_len != 0 ||
4800 smtp_state->cmds_cnt != 0 ||
4801 smtp_state->cmds_idx != 0 ||
56b74c8b 4802 smtp_state->curr_tx->mime_state == NULL || smtp_state->curr_tx->msg_head == NULL || /* MIME data structures */
c2dc6867
DA
4803 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
4804 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
260872cc 4805 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4806 goto end;
4807 }
4808
6530c3d0 4809 FLOWLOCK_WRLOCK(&f);
c2dc6867 4810 /* DATA . request */
675fa564
GL
4811 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4812 STREAM_TOSERVER, request4_end, request4_end_len);
c2dc6867
DA
4813 if (r != 0) {
4814 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 4815 FLOWLOCK_UNLOCK(&f);
c2dc6867
DA
4816 goto end;
4817 }
6530c3d0 4818 FLOWLOCK_UNLOCK(&f);
c2dc6867
DA
4819
4820 if (smtp_state->input_len != 0 ||
4821 smtp_state->cmds_cnt != 1 ||
4822 smtp_state->cmds_idx != 0 ||
4823 smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
56b74c8b 4824 smtp_state->curr_tx->mime_state == NULL || smtp_state->curr_tx->msg_head == NULL || /* MIME data structures */
c2dc6867 4825 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
260872cc 4826 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4827 goto end;
4828 }
4829
4830 SMTPState *state = (SMTPState *) f.alstate;
4831 FileContainer *files = state->files_ts;
4832 if (files != NULL && files->head != NULL) {
4833 File *file = files->head;
4834
4835 if(strncmp((const char *)file->name, "test.exe", 8) != 0){
4836 printf("smtp-mime file name is incorrect");
4837 goto end;
4838 }
569cc5d2
EL
4839 if (FileTrackedSize(file) != filesize){
4840 printf("smtp-mime file size %"PRIu64" is incorrect", FileDataSize(file));
c2dc6867
DA
4841 goto end;
4842 }
6467a5d5
TD
4843 static uint8_t org_binary[] = {
4844 0x4D, 0x5A, 0x00, 0x00, 0x50, 0x45, 0x00, 0x00,
c2dc6867
DA
4845 0x4C, 0x01, 0x01, 0x00, 0x6A, 0x2A, 0x58, 0xC3,
4846 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4847 0x04, 0x00, 0x03, 0x01, 0x0B, 0x01, 0x08, 0x00,
4848 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
4849 0x79, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
4850 0x79, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
4851 0x00, 0x00, 0x40, 0x00, 0x04, 0x00, 0x00, 0x00,
4852 0x04, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00,
4853 0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
4854 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00,
4855 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4856 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4857 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4858 0x00, 0x00, 0x00, 0x00, 0x5C, 0x5C, 0x36, 0x36,
4859 0x2E, 0x39, 0x33, 0x2E, 0x36, 0x38, 0x2E, 0x36,
4860 0x5C, 0x7A, 0x00, 0x00, 0x38,};
e43ce0a9
VJ
4861
4862 if (StreamingBufferCompareRawData(file->sb,
4863 org_binary, sizeof(org_binary)) != 1)
4864 {
4865 printf("smtp-mime file data incorrect\n");
4866 goto end;
c2dc6867
DA
4867 }
4868 }
4869
6530c3d0 4870 FLOWLOCK_WRLOCK(&f);
c2dc6867 4871 /* DATA . reply */
675fa564
GL
4872 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4873 STREAM_TOCLIENT, reply4_end, reply4_end_len);
c2dc6867
DA
4874 if (r != 0) {
4875 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 4876 FLOWLOCK_UNLOCK(&f);
c2dc6867
DA
4877 goto end;
4878 }
6530c3d0 4879 FLOWLOCK_UNLOCK(&f);
c2dc6867
DA
4880 if (smtp_state->input_len != 0 ||
4881 smtp_state->cmds_cnt != 0 ||
4882 smtp_state->cmds_idx != 0 ||
4883 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
260872cc 4884 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4885 goto end;
4886 }
4887
6530c3d0 4888 FLOWLOCK_WRLOCK(&f);
c2dc6867 4889 /* QUIT Request */
675fa564
GL
4890 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4891 STREAM_TOSERVER, request5, request5_len);
c2dc6867
DA
4892 if (r != 0) {
4893 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 4894 FLOWLOCK_UNLOCK(&f);
c2dc6867
DA
4895 goto end;
4896 }
6530c3d0 4897 FLOWLOCK_UNLOCK(&f);
c2dc6867
DA
4898 if (smtp_state->input_len != 0 ||
4899 smtp_state->cmds_cnt != 1 ||
4900 smtp_state->cmds_idx != 0 ||
4901 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4902 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
260872cc 4903 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4904 goto end;
4905 }
4906
6530c3d0 4907 FLOWLOCK_WRLOCK(&f);
c2dc6867 4908 /* QUIT Reply */
675fa564
GL
4909 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4910 STREAM_TOCLIENT, reply5, reply5_len);
c2dc6867
DA
4911 if (r != 0) {
4912 printf("smtp check returned %" PRId32 ", expected 0: ", r);
6530c3d0 4913 FLOWLOCK_UNLOCK(&f);
c2dc6867
DA
4914 goto end;
4915 }
6530c3d0 4916 FLOWLOCK_UNLOCK(&f);
c2dc6867
DA
4917 if (smtp_state->input_len != 0 ||
4918 smtp_state->cmds_cnt != 0 ||
4919 smtp_state->cmds_idx != 0 ||
4920 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
260872cc 4921 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
c2dc6867
DA
4922 goto end;
4923 }
4924
4925 result = 1;
260872cc
EL
4926end:
4927 if (alp_tctx != NULL)
4928 AppLayerParserThreadCtxFree(alp_tctx);
c2dc6867
DA
4929 StreamTcpFreeConfig(TRUE);
4930 FLOW_DESTROY(&f);
c2dc6867
DA
4931 return result;
4932}
4933
e43ce0a9 4934static int SMTPProcessDataChunkTest01(void){
c2dc6867
DA
4935 Flow f;
4936 FLOW_INITIALIZE(&f);
c81aaeda 4937 f.file_flags = FLOWFILE_NO_STORE_TS;
c2dc6867
DA
4938 MimeDecParseState *state = MimeDecInitParser(&f, NULL);
4939 int ret;
d2657bec 4940 ret = SMTPProcessDataChunk(NULL, 0, state);
c2dc6867 4941
52983bf3 4942 return ret == 0;
c2dc6867
DA
4943}
4944
4945
e43ce0a9 4946static int SMTPProcessDataChunkTest02(void){
c2dc6867
DA
4947 char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72,
4948 0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E,
4949 0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
4950 0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A,
4951 0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61,
4952 0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74,
4953 0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61,
4954 0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
4955 0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73,
4956 0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F,
4957 0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61,
4958 0x73, 0x65, 0x36, 0x34, 0x0D, 0x0A, 0x43, 0x6F,
4959 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x44, 0x69,
4960 0x73, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F,
4961 0x6E, 0x3A, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63,
4962 0x68, 0x6D, 0x65, 0x6E, 0x74, 0x3B, 0x20, 0x66,
4963 0x69, 0x6C, 0x65, 0x6E, 0x61, 0x6D, 0x65, 0x3D,
4964 0x22, 0x74, 0x65, 0x73, 0x74, 0x2E, 0x65, 0x78,
4965 0x65, 0x22, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x54,
4966 0x56, 0x6F, 0x41, 0x41, 0x46, 0x42, 0x46, 0x41,
4967 0x41, 0x42, 0x4D, 0x41, 0x51, 0x45, 0x41, 0x61,
4968 0x69, 0x70, 0x59, 0x77, 0x77, 0x41, 0x41, 0x41,
4969 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
4970 0x41, 0x41, 0x44, 0x41, 0x51, 0x73, 0x42, 0x43,
4971 0x41, 0x41, 0x42, 0x41, 0x41, 0x43, 0x41, 0x41,
4972 0x41, 0x41, 0x41, 0x41, 0x48, 0x6B, 0x41, 0x41,
4973 0x41, 0x41, 0x4D, 0x41, 0x41, 0x41, 0x41, 0x65,
4974 0x51, 0x41, 0x41, 0x41, 0x41, 0x77, 0x41, 0x41,
4975 0x41, 0x41, 0x41, 0x41, 0x45, 0x41, 0x41, 0x42,
4976 0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
4977 0x41, 0x42, 0x30, 0x41, 0x41, 0x41, 0x41, 0x49,
4978 0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
4979 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
4980 0x41, 0x45, 0x41, 0x41, 0x49, 0x67, 0x41, 0x41,
4981 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4982 0x67, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4983 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4984 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4985 0x41, 0x42, 0x63, 0x58, 0x44, 0x59, 0x32, 0x4C,
4986 0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C,
4987 0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F,
4988 0x41, 0x3D, 0x3D, 0x0D, 0x0A,};
4989
4990 Flow f;
4991 FLOW_INITIALIZE(&f);
4992 f.alstate = SMTPStateAlloc();
4993 MimeDecParseState *state = MimeDecInitParser(&f, NULL);
4994 ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT;
4995 state->body_begin = 1;
4996 int ret;
d2657bec 4997 ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state);
c2dc6867 4998
52983bf3 4999 return ret == 0;
c2dc6867
DA
5000}
5001
5002
5003
e43ce0a9 5004static int SMTPProcessDataChunkTest03(void){
c2dc6867
DA
5005 char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, };
5006 char mimemsg2[] = {0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, };
5007 char mimemsg3[] = {0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, };
5008 char mimemsg4[] = {0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A, };
5009 char mimemsg5[] = {0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, };
5010 char mimemsg6[] = {0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74, };
5011 char mimemsg7[] = {0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61, };
5012 char mimemsg8[] = {0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, };
5013 char mimemsg9[] = {0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73, };
5014 char mimemsg10[] = {0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F, };
5015 char mimemsg11[] = {0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61, };
5016 char mimemsg12[] = {0x73, 0x65, 0x36, 0x34, 0x0D, 0x0A, 0x43, 0x6F, };
5017
5018 Flow f;
5019 FLOW_INITIALIZE(&f);
5020 f.alstate = SMTPStateAlloc();
5021 MimeDecParseState *state = MimeDecInitParser(&f, NULL);
5022 ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT;
5023 int ret;
5024
5025 state->body_begin = 1;
d2657bec 5026 ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state);
c2dc6867
DA
5027 if(ret) goto end;
5028 state->body_begin = 0;
d2657bec 5029 ret = SMTPProcessDataChunk((uint8_t *)mimemsg2, sizeof(mimemsg2), state);
c2dc6867 5030 if(ret) goto end;
d2657bec 5031 ret = SMTPProcessDataChunk((uint8_t *)mimemsg3, sizeof(mimemsg3), state);
c2dc6867 5032 if(ret) goto end;
d2657bec 5033 ret = SMTPProcessDataChunk((uint8_t *)mimemsg4, sizeof(mimemsg4), state);
c2dc6867 5034 if(ret) goto end;
d2657bec 5035 ret = SMTPProcessDataChunk((uint8_t *)mimemsg5, sizeof(mimemsg5), state);
c2dc6867 5036 if(ret) goto end;
d2657bec 5037 ret = SMTPProcessDataChunk((uint8_t *)mimemsg6, sizeof(mimemsg6), state);
c2dc6867 5038 if(ret) goto end;
d2657bec 5039 ret = SMTPProcessDataChunk((uint8_t *)mimemsg7, sizeof(mimemsg7), state);
c2dc6867 5040 if(ret) goto end;
d2657bec 5041 ret = SMTPProcessDataChunk((uint8_t *)mimemsg8, sizeof(mimemsg8), state);
c2dc6867 5042 if(ret) goto end;
d2657bec 5043 ret = SMTPProcessDataChunk((uint8_t *)mimemsg9, sizeof(mimemsg9), state);
c2dc6867 5044 if(ret) goto end;
d2657bec 5045 ret = SMTPProcessDataChunk((uint8_t *)mimemsg10, sizeof(mimemsg10), state);
c2dc6867 5046 if(ret) goto end;
d2657bec 5047 ret = SMTPProcessDataChunk((uint8_t *)mimemsg11, sizeof(mimemsg11), state);
c2dc6867
DA
5048 if(ret) goto end;
5049 state->body_end = 1;
d2657bec 5050 ret = SMTPProcessDataChunk((uint8_t *)mimemsg12, sizeof(mimemsg12), state);
c2dc6867
DA
5051 if(ret) goto end;
5052
5053 end:
52983bf3 5054 return ret == 0;
c2dc6867
DA
5055}
5056
5057
e43ce0a9 5058static int SMTPProcessDataChunkTest04(void){
c2dc6867
DA
5059 char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, };
5060 char mimemsg2[] = {0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, };
5061 char mimemsg3[] = {0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, };
5062 char mimemsg4[] = {0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A, };
5063 char mimemsg5[] = {0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, };
5064 char mimemsg6[] = {0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74, };
5065 char mimemsg7[] = {0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61, };
5066 char mimemsg8[] = {0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, };
5067 char mimemsg9[] = {0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73, };
5068 char mimemsg10[] = {0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F, };
5069 char mimemsg11[] = {0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61, };
5070
5071 Flow f;
5072 FLOW_INITIALIZE(&f);
5073 f.alstate = SMTPStateAlloc();
5074 MimeDecParseState *state = MimeDecInitParser(&f, NULL);
5075 ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT;
5076 int ret = MIME_DEC_OK;
5077
5078 state->body_begin = 1;
d2657bec
GL
5079 if(SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state) != 0) goto end;
5080 if(SMTPProcessDataChunk((uint8_t *)mimemsg2, sizeof(mimemsg2), state) != 0) goto end;
5081 if(SMTPProcessDataChunk((uint8_t *)mimemsg3, sizeof(mimemsg3), state) != 0) goto end;
5082 if(SMTPProcessDataChunk((uint8_t *)mimemsg4, sizeof(mimemsg4), state) != 0) goto end;
5083 if(SMTPProcessDataChunk((uint8_t *)mimemsg5, sizeof(mimemsg5), state) != 0) goto end;
5084 if(SMTPProcessDataChunk((uint8_t *)mimemsg6, sizeof(mimemsg6), state) != 0) goto end;
5085 if(SMTPProcessDataChunk((uint8_t *)mimemsg7, sizeof(mimemsg7), state) != 0) goto end;
c2dc6867
DA
5086 state->body_begin = 0;
5087 state->body_end = 1;
d2657bec 5088 if(SMTPProcessDataChunk((uint8_t *)mimemsg8, sizeof(mimemsg8), state) != 0) goto end;
c2dc6867 5089 state->body_end = 0;
d2657bec
GL
5090 if(SMTPProcessDataChunk((uint8_t *)mimemsg9, sizeof(mimemsg9), state) != 0) goto end;
5091 if(SMTPProcessDataChunk((uint8_t *)mimemsg10, sizeof(mimemsg10), state) != 0) goto end;
5092 if(SMTPProcessDataChunk((uint8_t *)mimemsg11, sizeof(mimemsg11), state) != 0) goto end;
c2dc6867
DA
5093
5094 end:
52983bf3 5095 return ret == 0;
c2dc6867
DA
5096}
5097
e43ce0a9 5098static int SMTPProcessDataChunkTest05(void){
c2dc6867
DA
5099 char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72,
5100 0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E,
5101 0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
5102 0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A,
5103 0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C,
5104 0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F,
5105 0x41, 0x3D, 0x3D, 0x0D, 0x0A,};
5106
5107 Flow f;
7f700a13 5108 int ret;
c2dc6867
DA
5109 FLOW_INITIALIZE(&f);
5110 f.alstate = SMTPStateAlloc();
7f700a13 5111 FAIL_IF(f.alstate == NULL);
c2dc6867
DA
5112 MimeDecParseState *state = MimeDecInitParser(&f, NULL);
5113 ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT;
7f700a13 5114 FAIL_IF(state == NULL);
c2dc6867 5115 state->body_begin = 1;
d2657bec 5116 ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state);
7f700a13 5117 FAIL_IF(ret != 0);
c2dc6867 5118 state->body_begin = 0;
c2dc6867
DA
5119 SMTPState *smtp_state = (SMTPState *)((Flow *)state->data)->alstate;
5120 FileContainer *files = smtp_state->files_ts;
7f700a13 5121 FAIL_IF(files == NULL);
c2dc6867 5122 File *file = files->head;
7f700a13 5123 FAIL_IF(file == NULL);
d2657bec 5124 ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state);
7f700a13 5125 FAIL_IF(ret != 0);
569cc5d2 5126 FAIL_IF((uint32_t)FileDataSize(file) != 106);
7f700a13
VJ
5127 SMTPStateFree(smtp_state);
5128 FLOW_DESTROY(&f);
5129 PASS;
c2dc6867
DA
5130}
5131
87599bc7
AS
5132#endif /* UNITTESTS */
5133
576ec7da
AS
5134void SMTPParserRegisterTests(void)
5135{
87599bc7 5136#ifdef UNITTESTS
796dd522
JI
5137 UtRegisterTest("SMTPParserTest01", SMTPParserTest01);
5138 UtRegisterTest("SMTPParserTest02", SMTPParserTest02);
5139 UtRegisterTest("SMTPParserTest03", SMTPParserTest03);
5140 UtRegisterTest("SMTPParserTest04", SMTPParserTest04);
5141 UtRegisterTest("SMTPParserTest05", SMTPParserTest05);
5142 UtRegisterTest("SMTPParserTest06", SMTPParserTest06);
5143 UtRegisterTest("SMTPParserTest07", SMTPParserTest07);
5144 UtRegisterTest("SMTPParserTest08", SMTPParserTest08);
5145 UtRegisterTest("SMTPParserTest09", SMTPParserTest09);
5146 UtRegisterTest("SMTPParserTest10", SMTPParserTest10);
5147 UtRegisterTest("SMTPParserTest11", SMTPParserTest11);
5148 UtRegisterTest("SMTPParserTest12", SMTPParserTest12);
5149 UtRegisterTest("SMTPParserTest13", SMTPParserTest13);
5150 UtRegisterTest("SMTPParserTest14", SMTPParserTest14);
5151 UtRegisterTest("SMTPProcessDataChunkTest01", SMTPProcessDataChunkTest01);
5152 UtRegisterTest("SMTPProcessDataChunkTest02", SMTPProcessDataChunkTest02);
5153 UtRegisterTest("SMTPProcessDataChunkTest03", SMTPProcessDataChunkTest03);
5154 UtRegisterTest("SMTPProcessDataChunkTest04", SMTPProcessDataChunkTest04);
5155 UtRegisterTest("SMTPProcessDataChunkTest05", SMTPProcessDataChunkTest05);
87599bc7 5156#endif /* UNITTESTS */
4a6908d3 5157
576ec7da
AS
5158 return;
5159}