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