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