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