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