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