aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/suricata/src/app-layer-smtp.c
diff options
context:
space:
mode:
authorAshlee Young <ashlee@onosfw.com>2015-09-09 22:21:41 -0700
committerAshlee Young <ashlee@onosfw.com>2015-09-09 22:21:41 -0700
commit8879b125d26e8db1a5633de5a9c692eb2d1c4f83 (patch)
treec7259d85a991b83dfa85ab2e339360669fc1f58e /framework/src/suricata/src/app-layer-smtp.c
parent13d05bc8458758ee39cb829098241e89616717ee (diff)
suricata checkin based on commit id a4bce14770beee46a537eda3c3f6e8e8565d5d0a
Change-Id: I9a214fa0ee95e58fc640e50bd604dac7f42db48f
Diffstat (limited to 'framework/src/suricata/src/app-layer-smtp.c')
-rw-r--r--framework/src/suricata/src/app-layer-smtp.c4875
1 files changed, 4875 insertions, 0 deletions
diff --git a/framework/src/suricata/src/app-layer-smtp.c b/framework/src/suricata/src/app-layer-smtp.c
new file mode 100644
index 00000000..1951613d
--- /dev/null
+++ b/framework/src/suricata/src/app-layer-smtp.c
@@ -0,0 +1,4875 @@
+/* Copyright (C) 2007-2012 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/**
+ * \file
+ *
+ * \author Anoop Saldanha <anoopsaldanha@gmail.com>
+ */
+
+#include "suricata.h"
+#include "suricata-common.h"
+#include "debug.h"
+#include "decode.h"
+#include "threads.h"
+
+#include "stream-tcp-private.h"
+#include "stream-tcp-reassemble.h"
+#include "stream-tcp.h"
+#include "stream.h"
+
+#include "app-layer.h"
+#include "app-layer-detect-proto.h"
+#include "app-layer-protos.h"
+#include "app-layer-parser.h"
+#include "app-layer-smtp.h"
+
+#include "util-mpm.h"
+#include "util-debug.h"
+#include "util-byte.h"
+#include "util-unittest.h"
+#include "util-byte.h"
+#include "util-unittest-helper.h"
+#include "util-memcmp.h"
+#include "flow-util.h"
+
+#include "detect-engine.h"
+#include "detect-engine-state.h"
+#include "detect-parse.h"
+
+#include "decode-events.h"
+#include "conf.h"
+
+#include "util-mem.h"
+#include "util-misc.h"
+
+/* content-limit default value */
+#define FILEDATA_CONTENT_LIMIT 1000
+/* content-inspect-min-size default value */
+#define FILEDATA_CONTENT_INSPECT_MIN_SIZE 1000
+/* content-inspect-window default value */
+#define FILEDATA_CONTENT_INSPECT_WINDOW 1000
+
+#define SMTP_MAX_REQUEST_AND_REPLY_LINE_LENGTH 510
+
+#define SMTP_COMMAND_BUFFER_STEPS 5
+
+/* we are in process of parsing a fresh command. Just a placeholder. If we
+ * are not in STATE_COMMAND_DATA_MODE, we have to be in this mode */
+#define SMTP_PARSER_STATE_COMMAND_MODE 0x00
+/* we are in mode of parsing a command's data. Used when we are parsing tls
+ * or accepting the rfc 2822 mail after DATA command */
+#define SMTP_PARSER_STATE_COMMAND_DATA_MODE 0x01
+/* Used when we are still in the process of parsing a server command. Used
+ * with multi-line replies and the stream is fragmented before all the lines
+ * for a response is seen */
+#define SMTP_PARSER_STATE_PARSING_SERVER_RESPONSE 0x02
+/* Used to indicate that the parser has seen the first reply */
+#define SMTP_PARSER_STATE_FIRST_REPLY_SEEN 0x04
+/* Used to indicate that the parser is parsing a multiline reply */
+#define SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY 0x08
+
+/* Various SMTP commands
+ * We currently have var-ified just STARTTLS and DATA, since we need to them
+ * for state transitions. The rest are just indicate as OTHER_CMD. Other
+ * commands would be introduced as and when needed */
+#define SMTP_COMMAND_STARTTLS 1
+#define SMTP_COMMAND_DATA 2
+#define SMTP_COMMAND_BDAT 3
+/* not an actual command per se, but the mode where we accept the mail after
+ * DATA has it's own reply code for completion, from the server. We give this
+ * stage a pseudo command of it's own, so that we can add this to the command
+ * buffer to match with the reply */
+#define SMTP_COMMAND_DATA_MODE 4
+/* All other commands are represented by this var */
+#define SMTP_COMMAND_OTHER_CMD 5
+
+/* Different EHLO extensions. Not used now. */
+#define SMTP_EHLO_EXTENSION_PIPELINING
+#define SMTP_EHLO_EXTENSION_SIZE
+#define SMTP_EHLO_EXTENSION_DSN
+#define SMTP_EHLO_EXTENSION_STARTTLS
+#define SMTP_EHLO_EXTENSION_8BITMIME
+
+SCEnumCharMap smtp_decoder_event_table[ ] = {
+ { "INVALID_REPLY", SMTP_DECODER_EVENT_INVALID_REPLY },
+ { "UNABLE_TO_MATCH_REPLY_WITH_REQUEST",
+ SMTP_DECODER_EVENT_UNABLE_TO_MATCH_REPLY_WITH_REQUEST },
+ { "MAX_COMMAND_LINE_LEN_EXCEEDED",
+ SMTP_DECODER_EVENT_MAX_COMMAND_LINE_LEN_EXCEEDED },
+ { "MAX_REPLY_LINE_LEN_EXCEEDED",
+ SMTP_DECODER_EVENT_MAX_REPLY_LINE_LEN_EXCEEDED },
+ { "INVALID_PIPELINED_SEQUENCE",
+ SMTP_DECODER_EVENT_INVALID_PIPELINED_SEQUENCE },
+ { "BDAT_CHUNK_LEN_EXCEEDED",
+ SMTP_DECODER_EVENT_BDAT_CHUNK_LEN_EXCEEDED },
+ { "NO_SERVER_WELCOME_MESSAGE",
+ SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE },
+ { "TLS_REJECTED",
+ SMTP_DECODER_EVENT_TLS_REJECTED },
+ { "DATA_COMMAND_REJECTED",
+ SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED },
+
+ /* MIME Events */
+ { "MIME_PARSE_FAILED",
+ SMTP_DECODER_EVENT_MIME_PARSE_FAILED },
+ { "MIME_MALFORMED_MSG",
+ SMTP_DECODER_EVENT_MIME_MALFORMED_MSG },
+ { "MIME_INVALID_BASE64",
+ SMTP_DECODER_EVENT_MIME_INVALID_BASE64 },
+ { "MIME_INVALID_QP",
+ SMTP_DECODER_EVENT_MIME_INVALID_QP },
+ { "MIME_LONG_LINE",
+ SMTP_DECODER_EVENT_MIME_LONG_LINE },
+ { "MIME_LONG_ENC_LINE",
+ SMTP_DECODER_EVENT_MIME_LONG_ENC_LINE },
+ { "MIME_LONG_HEADER_NAME",
+ SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME },
+ { "MIME_LONG_HEADER_VALUE",
+ SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE },
+ { "MIME_LONG_BOUNDARY",
+ SMTP_DECODER_EVENT_MIME_BOUNDARY_TOO_LONG },
+
+ { NULL, -1 },
+};
+
+#define SMTP_MPM DEFAULT_MPM
+
+static MpmCtx *smtp_mpm_ctx = NULL;
+MpmThreadCtx *smtp_mpm_thread_ctx;
+
+/* smtp reply codes. If an entry is made here, please make a simultaneous
+ * entry in smtp_reply_map */
+enum {
+ SMTP_REPLY_211,
+ SMTP_REPLY_214,
+ SMTP_REPLY_220,
+ SMTP_REPLY_221,
+ SMTP_REPLY_235,
+ SMTP_REPLY_250,
+ SMTP_REPLY_251,
+ SMTP_REPLY_252,
+
+ SMTP_REPLY_334,
+ SMTP_REPLY_354,
+
+ SMTP_REPLY_421,
+ SMTP_REPLY_450,
+ SMTP_REPLY_451,
+ SMTP_REPLY_452,
+ SMTP_REPLY_455,
+
+ SMTP_REPLY_500,
+ SMTP_REPLY_501,
+ SMTP_REPLY_502,
+ SMTP_REPLY_503,
+ SMTP_REPLY_504,
+ SMTP_REPLY_550,
+ SMTP_REPLY_551,
+ SMTP_REPLY_552,
+ SMTP_REPLY_553,
+ SMTP_REPLY_554,
+ SMTP_REPLY_555,
+};
+
+SCEnumCharMap smtp_reply_map[ ] = {
+ { "211", SMTP_REPLY_211 },
+ { "214", SMTP_REPLY_214 },
+ { "220", SMTP_REPLY_220 },
+ { "221", SMTP_REPLY_221 },
+ { "235", SMTP_REPLY_235 },
+ { "250", SMTP_REPLY_250 },
+ { "251", SMTP_REPLY_251 },
+ { "252", SMTP_REPLY_252 },
+
+ { "334", SMTP_REPLY_334 },
+ { "354", SMTP_REPLY_354 },
+
+ { "421", SMTP_REPLY_421 },
+ { "450", SMTP_REPLY_450 },
+ { "451", SMTP_REPLY_451 },
+ { "452", SMTP_REPLY_452 },
+ { "455", SMTP_REPLY_455 },
+
+ { "500", SMTP_REPLY_500 },
+ { "501", SMTP_REPLY_501 },
+ { "502", SMTP_REPLY_502 },
+ { "503", SMTP_REPLY_503 },
+ { "504", SMTP_REPLY_504 },
+ { "550", SMTP_REPLY_550 },
+ { "551", SMTP_REPLY_551 },
+ { "552", SMTP_REPLY_552 },
+ { "553", SMTP_REPLY_553 },
+ { "554", SMTP_REPLY_554 },
+ { "555", SMTP_REPLY_555 },
+ { NULL, -1 },
+};
+
+/* Create SMTP config structure */
+SMTPConfig smtp_config = { 0, { 0, 0, 0, 0 }, 0, 0, 0};
+
+/**
+ * \brief Configure SMTP Mime Decoder by parsing out mime section of YAML
+ * config file
+ *
+ * \return none
+ */
+static void SMTPConfigure(void) {
+
+ SCEnter();
+ int ret = 0, val;
+ intmax_t imval;
+ uint32_t content_limit = 0;
+ uint32_t content_inspect_min_size = 0;
+ uint32_t content_inspect_window = 0;
+
+ ConfNode *config = ConfGetNode("app-layer.protocols.smtp.mime");
+ if (config != NULL) {
+
+ ret = ConfGetChildValueBool(config, "decode-mime", &val);
+ if (ret) {
+ smtp_config.decode_mime = val;
+ }
+
+ ret = ConfGetChildValueBool(config, "decode-base64", &val);
+ if (ret) {
+ smtp_config.mime_config.decode_base64 = val;
+ }
+
+ ret = ConfGetChildValueBool(config, "decode-quoted-printable", &val);
+ if (ret) {
+ smtp_config.mime_config.decode_quoted_printable = val;
+ }
+
+ ret = ConfGetChildValueInt(config, "header-value-depth", &imval);
+ if (ret) {
+ smtp_config.mime_config.header_value_depth = (uint32_t) imval;
+ }
+
+ ret = ConfGetChildValueBool(config, "extract-urls", &val);
+ if (ret) {
+ smtp_config.mime_config.extract_urls = val;
+ }
+ }
+
+ /* Pass mime config data to MimeDec API */
+ MimeDecSetConfig(&smtp_config.mime_config);
+
+ ConfNode *t = ConfGetNode("app-layer.protocols.smtp.inspected-tracker");
+ ConfNode *p = NULL;
+
+ if (t == NULL)
+ return;
+
+ TAILQ_FOREACH(p, &t->head, next) {
+ if (strcasecmp("content-limit", p->name) == 0) {
+ if (ParseSizeStringU32(p->val, &content_limit) < 0) {
+ SCLogWarning(SC_ERR_SIZE_PARSE, "Error parsing content-limit "
+ "from conf file - %s. Killing engine", p->val);
+ content_limit = FILEDATA_CONTENT_LIMIT;
+ }
+ }
+
+ if (strcasecmp("content-inspect-min-size", p->name) == 0) {
+ if (ParseSizeStringU32(p->val, &content_inspect_min_size) < 0) {
+ SCLogWarning(SC_ERR_SIZE_PARSE, "Error parsing content-inspect-min-size-limit "
+ "from conf file - %s. Killing engine", p->val);
+ content_inspect_min_size = FILEDATA_CONTENT_INSPECT_MIN_SIZE;
+ }
+ }
+
+ if (strcasecmp("content-inspect-window", p->name) == 0) {
+ if (ParseSizeStringU32(p->val, &content_inspect_window) < 0) {
+ SCLogWarning(SC_ERR_SIZE_PARSE, "Error parsing content-inspect-window "
+ "from conf file - %s. Killing engine", p->val);
+ content_inspect_window = FILEDATA_CONTENT_INSPECT_WINDOW;
+ }
+ }
+ }
+
+ SCReturn;
+}
+
+void SMTPSetEvent(SMTPState *s, uint8_t e)
+{
+ SCLogDebug("setting event %u", e);
+
+ if (s->curr_tx != NULL) {
+ AppLayerDecoderEventsSetEventRaw(&s->curr_tx->decoder_events, e);
+// s->events++;
+ return;
+ }
+ SCLogDebug("couldn't set event %u", e);
+}
+
+static SMTPTransaction *SMTPTransactionCreate(void)
+{
+ SMTPTransaction *tx = SCCalloc(1, sizeof(*tx));
+ if (tx == NULL) {
+ return NULL;
+ }
+
+ tx->mime_state = NULL;
+ return tx;
+}
+
+int SMTPProcessDataChunk(const uint8_t *chunk, uint32_t len,
+ MimeDecParseState *state) {
+
+ int ret = MIME_DEC_OK;
+ Flow *flow = (Flow *) state->data;
+ SMTPState *smtp_state = (SMTPState *) flow->alstate;
+ MimeDecEntity *entity = (MimeDecEntity *) state->stack->top->data;
+ FileContainer *files = NULL;
+ uint16_t flags = 0;
+
+ /* Set flags */
+ if (flow->flags & FLOW_FILE_NO_STORE_TS) {
+ flags |= FILE_NOSTORE;
+ }
+
+ if (flow->flags & FLOW_FILE_NO_MAGIC_TS) {
+ flags |= FILE_NOMAGIC;
+ }
+
+ if (flow->flags & FLOW_FILE_NO_MD5_TS) {
+ flags |= FILE_NOMD5;
+ }
+
+ /* Determine whether to process files */
+ if ((flags & (FILE_NOSTORE | FILE_NOMAGIC | FILE_NOMD5)) ==
+ (FILE_NOSTORE | FILE_NOMAGIC | FILE_NOMD5)) {
+ SCLogDebug("File content ignored");
+ return 0;
+ }
+
+ /* Find file */
+ if (entity->ctnt_flags & CTNT_IS_ATTACHMENT) {
+
+ /* Make sure file container allocated */
+ if (smtp_state->files_ts == NULL) {
+ smtp_state->files_ts = FileContainerAlloc();
+ if (smtp_state->files_ts == NULL) {
+ ret = MIME_DEC_ERR_MEM;
+ SCLogError(SC_ERR_MEM_ALLOC, "Could not create file container");
+ goto end;
+ }
+ }
+ files = smtp_state->files_ts;
+
+ /* Open file if necessary */
+ if (state->body_begin) {
+
+ if (SCLogDebugEnabled()) {
+ SCLogDebug("Opening file...%u bytes", len);
+ printf("File - ");
+ for (uint32_t i = 0; i < entity->filename_len; i++) {
+ printf("%c", entity->filename[i]);
+ }
+ printf("\n");
+ }
+
+ /* Set storage flag if applicable since only the first file in the
+ * flow seems to be processed by the 'filestore' detector */
+ if (files->head != NULL && (files->head->flags & FILE_STORE)) {
+ flags |= FILE_STORE;
+ }
+
+ if (FileOpenFile(files, (uint8_t *) entity->filename, entity->filename_len,
+ (uint8_t *) chunk, len, flags) == NULL) {
+ ret = MIME_DEC_ERR_DATA;
+ SCLogDebug("FileOpenFile() failed");
+ }
+
+ /* If close in the same chunk, then pass in empty bytes */
+ if (state->body_end) {
+
+ SCLogDebug("Closing file...%u bytes", len);
+
+ if (files->tail->state == FILE_STATE_OPENED) {
+ ret = FileCloseFile(files, (uint8_t *) NULL, 0, flags);
+ if (ret != 0) {
+ SCLogDebug("FileCloseFile() failed: %d", ret);
+ ret = MIME_DEC_ERR_DATA;
+ }
+ } else {
+ SCLogDebug("File already closed");
+ }
+ }
+ } else if (state->body_end) {
+ /* Close file */
+ SCLogDebug("Closing file...%u bytes", len);
+
+ if (files && files->tail && files->tail->state == FILE_STATE_OPENED) {
+ ret = FileCloseFile(files, (uint8_t *) chunk, len, flags);
+ if (ret != 0) {
+ SCLogDebug("FileCloseFile() failed: %d", ret);
+ ret = MIME_DEC_ERR_DATA;
+ }
+ } else {
+ SCLogDebug("File already closed");
+ }
+ } else {
+ /* Append data chunk to file */
+ SCLogDebug("Appending file...%u bytes", len);
+
+ /* 0 is ok, -2 is not stored, -1 is error */
+ ret = FileAppendData(files, (uint8_t *) chunk, len);
+ if (ret == -2) {
+ ret = 0;
+ SCLogDebug("FileAppendData() - file no longer being extracted");
+ } else if (ret < 0) {
+ SCLogDebug("FileAppendData() failed: %d", ret);
+ ret = MIME_DEC_ERR_DATA;
+ }
+ }
+
+ if (ret == 0) {
+ SCLogDebug("Successfully processed file data!");
+ }
+ } else {
+ SCLogDebug("Body not a Ctnt_attachment");
+ }
+
+ if (files != NULL) {
+ FilePrune(files);
+ }
+end:
+ SCReturnInt(ret);
+}
+
+/**
+ * \internal
+ * \brief Get the next line from input. It doesn't do any length validation.
+ *
+ * \param state The smtp state.
+ *
+ * \retval 0 On suceess.
+ * \retval -1 Either when we don't have any new lines to supply anymore or
+ * on failure.
+ */
+static int SMTPGetLine(SMTPState *state)
+{
+ SCEnter();
+ void *ptmp;
+
+ /* we have run out of input */
+ if (state->input_len <= 0)
+ return -1;
+
+ /* toserver */
+ if (state->direction == 0) {
+ if (state->ts_current_line_lf_seen == 1) {
+ /* we have seen the lf for the previous line. Clear the parser
+ * details to parse new line */
+ state->ts_current_line_lf_seen = 0;
+ if (state->ts_current_line_db == 1) {
+ state->ts_current_line_db = 0;
+ SCFree(state->ts_db);
+ state->ts_db = NULL;
+ state->ts_db_len = 0;
+ state->current_line = NULL;
+ state->current_line_len = 0;
+ }
+ }
+
+ uint8_t *lf_idx = memchr(state->input, 0x0a, state->input_len);
+
+ if (lf_idx == NULL) {
+ /* fragmented lines. Decoder event for special cases. Not all
+ * fragmented lines should be treated as a possible evasion
+ * attempt. With multi payload smtp chunks we can have valid
+ * cases of fragmentation. But within the same segment chunk
+ * if we see fragmentation then it's definitely something you
+ * should alert about */
+ if (state->ts_current_line_db == 0) {
+ state->ts_db = SCMalloc(state->input_len);
+ if (state->ts_db == NULL) {
+ return -1;
+ }
+ state->ts_current_line_db = 1;
+ memcpy(state->ts_db, state->input, state->input_len);
+ state->ts_db_len = state->input_len;
+ } else {
+ ptmp = SCRealloc(state->ts_db,
+ (state->ts_db_len + state->input_len));
+ if (ptmp == NULL) {
+ SCFree(state->ts_db);
+ state->ts_db = NULL;
+ state->ts_db_len = 0;
+ return -1;
+ }
+ state->ts_db = ptmp;
+
+ memcpy(state->ts_db + state->ts_db_len,
+ state->input, state->input_len);
+ state->ts_db_len += state->input_len;
+ } /* else */
+ state->input += state->input_len;
+ state->input_len = 0;
+
+ return -1;
+
+ } else {
+ state->ts_current_line_lf_seen = 1;
+
+ if (state->ts_current_line_db == 1) {
+ ptmp = SCRealloc(state->ts_db,
+ (state->ts_db_len + (lf_idx + 1 - state->input)));
+ if (ptmp == NULL) {
+ SCFree(state->ts_db);
+ state->ts_db = NULL;
+ state->ts_db_len = 0;
+ return -1;
+ }
+ state->ts_db = ptmp;
+
+ memcpy(state->ts_db + state->ts_db_len,
+ state->input, (lf_idx + 1 - state->input));
+ state->ts_db_len += (lf_idx + 1 - state->input);
+
+ if (state->ts_db_len > 1 &&
+ state->ts_db[state->ts_db_len - 2] == 0x0D) {
+ state->ts_db_len -= 2;
+ state->current_line_delimiter_len = 2;
+ } else {
+ state->ts_db_len -= 1;
+ state->current_line_delimiter_len = 1;
+ }
+
+ state->current_line = state->ts_db;
+ state->current_line_len = state->ts_db_len;
+
+ } else {
+ state->current_line = state->input;
+ state->current_line_len = lf_idx - state->input;
+
+ if (state->input != lf_idx &&
+ *(lf_idx - 1) == 0x0D) {
+ state->current_line_len--;
+ state->current_line_delimiter_len = 2;
+ } else {
+ state->current_line_delimiter_len = 1;
+ }
+ }
+
+ state->input_len -= (lf_idx - state->input) + 1;
+ state->input = (lf_idx + 1);
+
+ return 0;
+ }
+
+ /* toclient */
+ } else {
+ if (state->tc_current_line_lf_seen == 1) {
+ /* we have seen the lf for the previous line. Clear the parser
+ * details to parse new line */
+ state->tc_current_line_lf_seen = 0;
+ if (state->tc_current_line_db == 1) {
+ state->tc_current_line_db = 0;
+ SCFree(state->tc_db);
+ state->tc_db = NULL;
+ state->tc_db_len = 0;
+ state->current_line = NULL;
+ state->current_line_len = 0;
+ }
+ }
+
+ uint8_t *lf_idx = memchr(state->input, 0x0a, state->input_len);
+
+ if (lf_idx == NULL) {
+ /* fragmented lines. Decoder event for special cases. Not all
+ * fragmented lines should be treated as a possible evasion
+ * attempt. With multi payload smtp chunks we can have valid
+ * cases of fragmentation. But within the same segment chunk
+ * if we see fragmentation then it's definitely something you
+ * should alert about */
+ if (state->tc_current_line_db == 0) {
+ state->tc_db = SCMalloc(state->input_len);
+ if (state->tc_db == NULL) {
+ return -1;
+ }
+ state->tc_current_line_db = 1;
+ memcpy(state->tc_db, state->input, state->input_len);
+ state->tc_db_len = state->input_len;
+ } else {
+ ptmp = SCRealloc(state->tc_db,
+ (state->tc_db_len + state->input_len));
+ if (ptmp == NULL) {
+ SCFree(state->tc_db);
+ state->tc_db = NULL;
+ state->tc_db_len = 0;
+ return -1;
+ }
+ state->tc_db = ptmp;
+
+ memcpy(state->tc_db + state->tc_db_len,
+ state->input, state->input_len);
+ state->tc_db_len += state->input_len;
+ } /* else */
+ state->input += state->input_len;
+ state->input_len = 0;
+
+ return -1;
+
+ } else {
+ state->tc_current_line_lf_seen = 1;
+
+ if (state->tc_current_line_db == 1) {
+ ptmp = SCRealloc(state->tc_db,
+ (state->tc_db_len + (lf_idx + 1 - state->input)));
+ if (ptmp == NULL) {
+ SCFree(state->tc_db);
+ state->tc_db = NULL;
+ state->tc_db_len = 0;
+ return -1;
+ }
+ state->tc_db = ptmp;
+
+ memcpy(state->tc_db + state->tc_db_len,
+ state->input, (lf_idx + 1 - state->input));
+ state->tc_db_len += (lf_idx + 1 - state->input);
+
+ if (state->tc_db_len > 1 &&
+ state->tc_db[state->tc_db_len - 2] == 0x0D) {
+ state->tc_db_len -= 2;
+ state->current_line_delimiter_len = 2;
+ } else {
+ state->tc_db_len -= 1;
+ state->current_line_delimiter_len = 1;
+ }
+
+ state->current_line = state->tc_db;
+ state->current_line_len = state->tc_db_len;
+
+ } else {
+ state->current_line = state->input;
+ state->current_line_len = lf_idx - state->input;
+
+ if (state->input != lf_idx &&
+ *(lf_idx - 1) == 0x0D) {
+ state->current_line_len--;
+ state->current_line_delimiter_len = 2;
+ } else {
+ state->current_line_delimiter_len = 1;
+ }
+ }
+
+ state->input_len -= (lf_idx - state->input) + 1;
+ state->input = (lf_idx + 1);
+
+ return 0;
+ } /* else - if (lf_idx == NULL) */
+ }
+
+}
+
+static int SMTPInsertCommandIntoCommandBuffer(uint8_t command, SMTPState *state, Flow *f)
+{
+ SCEnter();
+ void *ptmp;
+
+ if (state->cmds_cnt >= state->cmds_buffer_len) {
+ int increment = SMTP_COMMAND_BUFFER_STEPS;
+ if ((int)(state->cmds_buffer_len + SMTP_COMMAND_BUFFER_STEPS) > (int)USHRT_MAX) {
+ increment = USHRT_MAX - state->cmds_buffer_len;
+ }
+
+ ptmp = SCRealloc(state->cmds,
+ sizeof(uint8_t) * (state->cmds_buffer_len + increment));
+ if (ptmp == NULL) {
+ SCFree(state->cmds);
+ state->cmds = NULL;
+ SCLogDebug("SCRealloc failure");
+ return -1;
+ }
+ state->cmds = ptmp;
+
+ state->cmds_buffer_len += increment;
+ }
+ if (state->cmds_cnt >= 1 &&
+ ((state->cmds[state->cmds_cnt - 1] == SMTP_COMMAND_STARTTLS) ||
+ (state->cmds[state->cmds_cnt - 1] == SMTP_COMMAND_DATA))) {
+ /* decoder event */
+ SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_PIPELINED_SEQUENCE);
+ /* we have to have EHLO, DATA, VRFY, EXPN, TURN, QUIT, NOOP,
+ * STARTTLS as the last command in pipelined mode */
+ }
+
+ /** \todo decoder event */
+ if ((int)(state->cmds_cnt + 1) > (int)USHRT_MAX) {
+ SCLogDebug("command buffer overflow");
+ return -1;
+ }
+
+ state->cmds[state->cmds_cnt] = command;
+ state->cmds_cnt++;
+
+ return 0;
+}
+
+static int SMTPProcessCommandBDAT(SMTPState *state, Flow *f,
+ AppLayerParserState *pstate)
+{
+ SCEnter();
+
+ state->bdat_chunk_idx += (state->current_line_len +
+ state->current_line_delimiter_len);
+ if (state->bdat_chunk_idx > state->bdat_chunk_len) {
+ state->parser_state &= ~SMTP_PARSER_STATE_COMMAND_DATA_MODE;
+ /* decoder event */
+ SMTPSetEvent(state, SMTP_DECODER_EVENT_BDAT_CHUNK_LEN_EXCEEDED);
+ SCReturnInt(-1);
+ } else if (state->bdat_chunk_idx == state->bdat_chunk_len) {
+ state->parser_state &= ~SMTP_PARSER_STATE_COMMAND_DATA_MODE;
+ }
+
+ SCReturnInt(0);
+}
+
+static int SMTPProcessCommandDATA(SMTPState *state, Flow *f,
+ AppLayerParserState *pstate)
+{
+ SCEnter();
+
+ if (!(state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
+ /* looks like are still waiting for a confirmination from the server */
+ return 0;
+ }
+
+ if (state->current_line_len == 1 && state->current_line[0] == '.') {
+ state->parser_state &= ~SMTP_PARSER_STATE_COMMAND_DATA_MODE;
+ /* kinda like a hack. The mail sent in DATA mode, would be
+ * acknowledged with a reply. We insert a dummy command to
+ * the command buffer to be used by the reply handler to match
+ * the reply received */
+ SMTPInsertCommandIntoCommandBuffer(SMTP_COMMAND_DATA_MODE, state, f);
+
+ if (smtp_config.decode_mime) {
+ /* Complete parsing task */
+ int ret = MimeDecParseComplete(state->curr_tx->mime_state);
+ if (ret != MIME_DEC_OK) {
+
+ SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_PARSE_FAILED);
+ SCLogDebug("MimeDecParseComplete() function failed");
+ }
+
+ /* Generate decoder events */
+ MimeDecEntity *msg = state->curr_tx->mime_state->msg;
+ if (msg->anomaly_flags & ANOM_INVALID_BASE64) {
+ SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_INVALID_BASE64);
+ }
+ if (msg->anomaly_flags & ANOM_INVALID_QP) {
+ SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_INVALID_QP);
+ }
+ if (msg->anomaly_flags & ANOM_LONG_LINE) {
+ SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_LINE);
+ }
+ if (msg->anomaly_flags & ANOM_LONG_ENC_LINE) {
+ SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_ENC_LINE);
+ }
+ if (msg->anomaly_flags & ANOM_LONG_HEADER_NAME) {
+ SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME);
+ }
+ if (msg->anomaly_flags & ANOM_LONG_HEADER_VALUE) {
+ SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE);
+ }
+ if (msg->anomaly_flags & ANOM_MALFORMED_MSG) {
+ SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_MALFORMED_MSG);
+ }
+ if (msg->anomaly_flags & ANOM_LONG_BOUNDARY) {
+ SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_BOUNDARY_TOO_LONG);
+ }
+ }
+ state->curr_tx->done = 1;
+ SCLogDebug("marked tx as done");
+ }
+
+ /* If DATA, then parse out a MIME message */
+ if (state->current_command == SMTP_COMMAND_DATA &&
+ (state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
+
+ if (smtp_config.decode_mime && state->curr_tx->mime_state) {
+ int ret = MimeDecParseLine((const uint8_t *) state->current_line,
+ state->current_line_len, state->curr_tx->mime_state);
+ if (ret != MIME_DEC_OK) {
+ SCLogDebug("MimeDecParseLine() function returned an error code: %d", ret);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int SMTPProcessCommandSTARTTLS(SMTPState *state, Flow *f,
+ AppLayerParserState *pstate)
+{
+ return 0;
+}
+
+static int SMTPProcessReply(SMTPState *state, Flow *f,
+ AppLayerParserState *pstate)
+{
+ SCEnter();
+
+ uint64_t reply_code = 0;
+ PatternMatcherQueue *pmq = state->thread_local_data;
+
+ /* the reply code has to contain at least 3 bytes, to hold the 3 digit
+ * reply code */
+ if (state->current_line_len < 3) {
+ /* decoder event */
+ SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY);
+ return -1;
+ }
+
+ if (state->current_line_len >= 4) {
+ if (state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY) {
+ if (state->current_line[3] != '-') {
+ state->parser_state &= ~SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY;
+ }
+ } else {
+ if (state->current_line[3] == '-') {
+ state->parser_state |= SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY;
+ }
+ }
+ } else {
+ if (state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY) {
+ state->parser_state &= ~SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY;
+ }
+ }
+
+ /* I don't like this pmq reset here. We'll devise a method later, that
+ * should make the use of the mpm very efficient */
+ PmqReset(pmq);
+ int mpm_cnt = mpm_table[SMTP_MPM].Search(smtp_mpm_ctx, smtp_mpm_thread_ctx,
+ pmq, state->current_line,
+ 3);
+ if (mpm_cnt == 0) {
+ /* set decoder event - reply code invalid */
+ SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY);
+ SCLogDebug("invalid reply code %02x %02x %02x",
+ state->current_line[0], state->current_line[1], state->current_line[2]);
+ SCReturnInt(-1);
+ }
+ reply_code = smtp_reply_map[pmq->pattern_id_array[0]].enum_value;
+
+ if (state->cmds_idx == state->cmds_cnt) {
+ if (!(state->parser_state & SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
+ state->parser_state |= SMTP_PARSER_STATE_FIRST_REPLY_SEEN;
+ if (reply_code == SMTP_REPLY_220)
+ SCReturnInt(0);
+ else
+ SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY);
+ } else {
+ /* decoder event - unable to match reply with request */
+ SCLogDebug("unable to match reply with request");
+ SCReturnInt(-1);
+ }
+ }
+
+ if (state->cmds_cnt == 0) {
+ /* reply but not a command we have stored, fall through */
+ } else if (state->cmds[state->cmds_idx] == SMTP_COMMAND_STARTTLS) {
+ if (reply_code == SMTP_REPLY_220) {
+ /* we are entering STARRTTLS data mode */
+ state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE;
+ AppLayerParserStateSetFlag(pstate,
+ APP_LAYER_PARSER_NO_INSPECTION |
+ APP_LAYER_PARSER_NO_REASSEMBLY);
+ } else {
+ /* decoder event */
+ SMTPSetEvent(state, SMTP_DECODER_EVENT_TLS_REJECTED);
+ }
+ } else if (state->cmds[state->cmds_idx] == SMTP_COMMAND_DATA) {
+ if (reply_code == SMTP_REPLY_354) {
+ /* Next comes the mail for the DATA command in toserver direction */
+ state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE;
+ } else {
+ /* decoder event */
+ SMTPSetEvent(state, SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED);
+ }
+ } else {
+ /* we don't care for any other command for now */
+ /* check if reply falls in the valid list of replies for SMTP. If not
+ * decoder event */
+ }
+
+ /* if it is a multi-line reply, we need to move the index only once for all
+ * the line of the reply. We unset the multiline flag on the last
+ * line of the multiline reply, following which we increment the index */
+ if (!(state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY)) {
+ state->cmds_idx++;
+ }
+
+ /* if we have matched all the buffered commands, reset the cnt and index */
+ if (state->cmds_idx == state->cmds_cnt) {
+ state->cmds_cnt = 0;
+ state->cmds_idx = 0;
+ }
+
+ return 0;
+}
+
+static int SMTPParseCommandBDAT(SMTPState *state)
+{
+ SCEnter();
+
+ int i = 4;
+ while (i < state->current_line_len) {
+ if (state->current_line[i] != ' ') {
+ break;
+ }
+ i++;
+ }
+ if (i == 4) {
+ /* decoder event */
+ return -1;
+ }
+ if (i == state->current_line_len) {
+ /* decoder event */
+ return -1;
+ }
+ char *endptr = NULL;
+ state->bdat_chunk_len = strtoul((const char *)state->current_line + i,
+ (char **)&endptr, 10);
+ if ((uint8_t *)endptr == state->current_line + i) {
+ /* decoder event */
+ return -1;
+ }
+
+ return 0;
+}
+
+/* consider 'rset' and 'quit' to be part of the existing state */
+static int NoNewTx(SMTPState *state)
+{
+ if (!(state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
+ if (state->current_line_len >= 4 &&
+ SCMemcmpLowercase("rset", state->current_line, 4) == 0) {
+ return 1;
+ } else if (state->current_line_len >= 4 &&
+ SCMemcmpLowercase("quit", state->current_line, 4) == 0) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int SMTPProcessRequest(SMTPState *state, Flow *f,
+ AppLayerParserState *pstate)
+{
+ SCEnter();
+ SMTPTransaction *tx = state->curr_tx;
+
+ if (state->curr_tx == NULL || (state->curr_tx->done && !NoNewTx(state))) {
+ tx = SMTPTransactionCreate();
+ if (tx == NULL)
+ return -1;
+ state->curr_tx = tx;
+ TAILQ_INSERT_TAIL(&state->tx_list, tx, next);
+ tx->tx_id = state->tx_cnt++;
+ }
+
+ if (!(state->parser_state & SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
+ SMTPSetEvent(state, SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE);
+ }
+
+ /* there are 2 commands that can push it into this COMMAND_DATA mode -
+ * STARTTLS and DATA */
+ if (!(state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
+ int r = 0;
+
+ if (state->current_line_len >= 8 &&
+ SCMemcmpLowercase("starttls", state->current_line, 8) == 0) {
+ state->current_command = SMTP_COMMAND_STARTTLS;
+ } else if (state->current_line_len >= 4 &&
+ SCMemcmpLowercase("data", state->current_line, 4) == 0) {
+ state->current_command = SMTP_COMMAND_DATA;
+ if (smtp_config.decode_mime) {
+ tx->mime_state = MimeDecInitParser(f, SMTPProcessDataChunk);
+ if (tx->mime_state == NULL) {
+ SCLogError(SC_ERR_MEM_ALLOC, "MimeDecInitParser() failed to "
+ "allocate data");
+ return MIME_DEC_ERR_MEM;
+ }
+
+ /* Add new MIME message to end of list */
+ if (tx->msg_head == NULL) {
+ tx->msg_head = tx->mime_state->msg;
+ tx->msg_tail = tx->mime_state->msg;
+ }
+ else {
+ tx->msg_tail->next = tx->mime_state->msg;
+ tx->msg_tail = tx->mime_state->msg;
+ }
+ }
+
+ } else if (state->current_line_len >= 4 &&
+ SCMemcmpLowercase("bdat", state->current_line, 4) == 0) {
+ r = SMTPParseCommandBDAT(state);
+ if (r == -1) {
+ SCReturnInt(-1);
+ }
+ state->current_command = SMTP_COMMAND_BDAT;
+ state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE;
+ } else {
+ state->current_command = SMTP_COMMAND_OTHER_CMD;
+ }
+
+ /* Every command is inserted into a command buffer, to be matched
+ * against reply(ies) sent by the server */
+ if (SMTPInsertCommandIntoCommandBuffer(state->current_command,
+ state, f) == -1) {
+ SCReturnInt(-1);
+ }
+
+ SCReturnInt(r);
+ }
+
+ switch (state->current_command) {
+ case SMTP_COMMAND_STARTTLS:
+ return SMTPProcessCommandSTARTTLS(state, f, pstate);
+
+ case SMTP_COMMAND_DATA:
+ return SMTPProcessCommandDATA(state, f, pstate);
+
+ case SMTP_COMMAND_BDAT:
+ return SMTPProcessCommandBDAT(state, f, pstate);
+
+ default:
+ /* we have nothing to do with any other command at this instant.
+ * Just let it go through */
+ SCReturnInt(0);
+ }
+}
+
+static int SMTPParse(int direction, Flow *f, SMTPState *state,
+ AppLayerParserState *pstate, uint8_t *input,
+ uint32_t input_len,
+ PatternMatcherQueue *local_data)
+{
+ SCEnter();
+
+ if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) {
+ SCReturnInt(1);
+ } else if (input == NULL || input_len == 0) {
+ SCReturnInt(-1);
+ }
+
+ state->input = input;
+ state->input_len = input_len;
+ state->direction = direction;
+ state->thread_local_data = local_data;
+
+ /* toserver */
+ if (direction == 0) {
+ while (SMTPGetLine(state) >= 0) {
+ if (SMTPProcessRequest(state, f, pstate) == -1)
+ SCReturnInt(-1);
+ }
+
+ /* toclient */
+ } else {
+ while (SMTPGetLine(state) >= 0) {
+ if (SMTPProcessReply(state, f, pstate) == -1)
+ SCReturnInt(-1);
+ }
+ }
+
+ SCReturnInt(0);
+}
+
+static int SMTPParseClientRecord(Flow *f, void *alstate,
+ AppLayerParserState *pstate,
+ uint8_t *input, uint32_t input_len,
+ void *local_data)
+{
+ SCEnter();
+
+ /* first arg 0 is toserver */
+ return SMTPParse(0, f, alstate, pstate, input, input_len, local_data);
+}
+
+static int SMTPParseServerRecord(Flow *f, void *alstate,
+ AppLayerParserState *pstate,
+ uint8_t *input, uint32_t input_len,
+ void *local_data)
+{
+ SCEnter();
+
+ /* first arg 1 is toclient */
+ return SMTPParse(1, f, alstate, pstate, input, input_len, local_data);
+
+ return 0;
+}
+
+/**
+ * \internal
+ * \brief Function to allocate SMTP state memory.
+ */
+void *SMTPStateAlloc(void)
+{
+ SMTPState *smtp_state = SCMalloc(sizeof(SMTPState));
+ if (unlikely(smtp_state == NULL))
+ return NULL;
+ memset(smtp_state, 0, sizeof(SMTPState));
+
+ smtp_state->cmds = SCMalloc(sizeof(uint8_t) *
+ SMTP_COMMAND_BUFFER_STEPS);
+ if (smtp_state->cmds == NULL) {
+ SCFree(smtp_state);
+ return NULL;
+ }
+ smtp_state->cmds_buffer_len = SMTP_COMMAND_BUFFER_STEPS;
+
+ TAILQ_INIT(&smtp_state->tx_list);
+
+ return smtp_state;
+}
+
+static void *SMTPLocalStorageAlloc(void)
+{
+ /* needed by the mpm */
+ PatternMatcherQueue *pmq = SCMalloc(sizeof(PatternMatcherQueue));
+ if (unlikely(pmq == NULL)) {
+ exit(EXIT_FAILURE);
+ }
+ PmqSetup(pmq,
+ sizeof(smtp_reply_map)/sizeof(SCEnumCharMap) - 2);
+
+ return pmq;
+}
+
+static void SMTPLocalStorageFree(void *pmq)
+{
+ if (pmq != NULL) {
+ PmqFree(pmq);
+ SCFree(pmq);
+ }
+
+ return;
+}
+
+static void SMTPTransactionFree(SMTPTransaction *tx, SMTPState *state)
+{
+ if (tx->mime_state != NULL) {
+ MimeDecDeInitParser(tx->mime_state);
+ }
+ /* Free list of MIME message recursively */
+ MimeDecFreeEntity(tx->msg_head);
+
+ if (tx->decoder_events != NULL)
+ AppLayerDecoderEventsFreeEvents(&tx->decoder_events);
+
+ if (tx->de_state != NULL)
+ DetectEngineStateFree(tx->de_state);
+#if 0
+ if (tx->decoder_events->cnt <= smtp_state->events)
+ smtp_state->events -= tx->decoder_events->cnt;
+ else
+ smtp_state->events = 0;
+#endif
+ SCFree(tx);
+}
+
+/**
+ * \internal
+ * \brief Function to free SMTP state memory.
+ */
+static void SMTPStateFree(void *p)
+{
+ SMTPState *smtp_state = (SMTPState *)p;
+
+ if (smtp_state->cmds != NULL) {
+ SCFree(smtp_state->cmds);
+ }
+ if (smtp_state->ts_current_line_db) {
+ SCFree(smtp_state->ts_db);
+ }
+ if (smtp_state->tc_current_line_db) {
+ SCFree(smtp_state->tc_db);
+ }
+
+ FileContainerFree(smtp_state->files_ts);
+
+ SMTPTransaction *tx = NULL;
+ while ((tx = TAILQ_FIRST(&smtp_state->tx_list))) {
+ TAILQ_REMOVE(&smtp_state->tx_list, tx, next);
+ SMTPTransactionFree(tx, smtp_state);
+ }
+
+ SCFree(smtp_state);
+
+ return;
+}
+
+static void SMTPSetMpmState(void)
+{
+ smtp_mpm_ctx = SCMalloc(sizeof(MpmCtx));
+ if (unlikely(smtp_mpm_ctx == NULL)) {
+ exit(EXIT_FAILURE);
+ }
+ memset(smtp_mpm_ctx, 0, sizeof(MpmCtx));
+ MpmInitCtx(smtp_mpm_ctx, SMTP_MPM);
+
+ smtp_mpm_thread_ctx = SCMalloc(sizeof(MpmThreadCtx));
+ if (unlikely(smtp_mpm_thread_ctx == NULL)) {
+ exit(EXIT_FAILURE);
+ }
+ memset(smtp_mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
+ MpmInitThreadCtx(smtp_mpm_thread_ctx, SMTP_MPM, 0);
+
+ uint32_t i = 0;
+ for (i = 0; i < sizeof(smtp_reply_map)/sizeof(SCEnumCharMap) - 1; i++) {
+ SCEnumCharMap *map = &smtp_reply_map[i];
+ /* The third argument is 3, because reply code is always 3 bytes. */
+ MpmAddPatternCI(smtp_mpm_ctx, (uint8_t *)map->enum_name, 3,
+ 0 /* defunct */, 0 /* defunct */,
+ i /* pattern id */, 0, 0 /* no flags */);
+ }
+
+ mpm_table[SMTP_MPM].Prepare(smtp_mpm_ctx);
+}
+
+int SMTPStateGetEventInfo(const char *event_name,
+ int *event_id, AppLayerEventType *event_type)
+{
+ *event_id = SCMapEnumNameToValue(event_name, smtp_decoder_event_table);
+ if (*event_id == -1) {
+ SCLogError(SC_ERR_INVALID_ENUM_MAP, "event \"%s\" not present in "
+ "smtp's enum map table.", event_name);
+ /* yes this is fatal */
+ return -1;
+ }
+
+ *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
+
+ return 0;
+}
+
+static int SMTPRegisterPatternsForProtocolDetection(void)
+{
+ if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMTP,
+ "EHLO", 4, 0, STREAM_TOSERVER) < 0)
+ {
+ return -1;
+ }
+ if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMTP,
+ "HELO", 4, 0, STREAM_TOSERVER) < 0)
+ {
+ return -1;
+ }
+ if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMTP,
+ "QUIT", 4, 0, STREAM_TOSERVER) < 0)
+ {
+ return -1;
+ }
+
+ return 0;
+}
+
+static void SMTPStateTransactionFree (void *state, uint64_t tx_id)
+{
+ SMTPState *smtp_state = state;
+ SMTPTransaction *tx = NULL;
+ TAILQ_FOREACH(tx, &smtp_state->tx_list, next) {
+ if (tx_id < tx->tx_id)
+ break;
+ else if (tx_id > tx->tx_id)
+ continue;
+
+ if (tx == smtp_state->curr_tx)
+ smtp_state->curr_tx = NULL;
+ TAILQ_REMOVE(&smtp_state->tx_list, tx, next);
+ SMTPTransactionFree(tx, state);
+ break;
+ }
+
+
+}
+
+/** \retval cnt highest tx id */
+static uint64_t SMTPStateGetTxCnt(void *state)
+{
+ uint64_t cnt = 0;
+ SMTPState *smtp_state = state;
+ if (smtp_state) {
+ cnt = smtp_state->tx_cnt;
+ }
+ SCLogDebug("returning %"PRIu64, cnt);
+ return cnt;
+}
+
+static void *SMTPStateGetTx(void *state, uint64_t id)
+{
+ SMTPState *smtp_state = state;
+ if (smtp_state) {
+ SMTPTransaction *tx = NULL;
+
+ if (smtp_state->curr_tx == NULL)
+ return NULL;
+ if (smtp_state->curr_tx->tx_id == id)
+ return smtp_state->curr_tx;
+
+ TAILQ_FOREACH(tx, &smtp_state->tx_list, next) {
+ if (tx->tx_id == id)
+ return tx;
+ }
+ }
+ return NULL;
+
+}
+
+static int SMTPStateGetAlstateProgressCompletionStatus(uint8_t direction) {
+ return 1;
+}
+
+static int SMTPStateGetAlstateProgress(void *vtx, uint8_t direction)
+{
+ SMTPTransaction *tx = vtx;
+ return tx->done;
+}
+
+static FileContainer *SMTPStateGetFiles(void *state, uint8_t direction)
+{
+ if (state == NULL)
+ return NULL;
+
+ SMTPState *smtp_state = (SMTPState *)state;
+
+ if (direction & STREAM_TOCLIENT) {
+ SCReturnPtr(NULL, "FileContainer");
+ } else {
+ SCLogDebug("smtp_state->files_ts %p", smtp_state->files_ts);
+ SCReturnPtr(smtp_state->files_ts, "FileContainer");
+ }
+}
+
+static void SMTPStateTruncate(void *state, uint8_t direction)
+{
+ FileContainer *fc = SMTPStateGetFiles(state, direction);
+ if (fc != NULL) {
+ SCLogDebug("truncating stream, closing files in %s direction (container %p)",
+ direction & STREAM_TOCLIENT ? "STREAM_TOCLIENT" : "STREAM_TOSERVER", fc);
+ FileTruncateAllOpenFiles(fc);
+ }
+}
+
+static AppLayerDecoderEvents *SMTPGetEvents(void *state, uint64_t tx_id)
+{
+ SCLogDebug("get SMTP events for TX %"PRIu64, tx_id);
+
+ SMTPTransaction *tx = SMTPStateGetTx(state, tx_id);
+ if (tx != NULL) {
+ return tx->decoder_events;
+ }
+ return NULL;
+}
+
+static DetectEngineState *SMTPGetTxDetectState(void *vtx)
+{
+ SMTPTransaction *tx = (SMTPTransaction *)vtx;
+ return tx->de_state;
+}
+
+static int SMTPSetTxDetectState(void *state, void *vtx, DetectEngineState *s)
+{
+ SMTPTransaction *tx = (SMTPTransaction *)vtx;
+ tx->de_state = s;
+ return 0;
+}
+
+/**
+ * \brief Register the SMTP Protocol parser.
+ */
+void RegisterSMTPParsers(void)
+{
+ char *proto_name = "smtp";
+
+ if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
+ AppLayerProtoDetectRegisterProtocol(ALPROTO_SMTP, proto_name);
+ if (SMTPRegisterPatternsForProtocolDetection() < 0 )
+ return;
+ } else {
+ SCLogInfo("Protocol detection and parser disabled for %s protocol.",
+ proto_name);
+ return;
+ }
+
+ if (AppLayerParserConfParserEnabled("tcp", proto_name)) {
+ AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateAlloc, SMTPStateFree);
+
+ AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_SMTP, STREAM_TOSERVER,
+ SMTPParseClientRecord);
+ AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_SMTP, STREAM_TOCLIENT,
+ SMTPParseServerRecord);
+
+ AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetEventInfo);
+ AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetEvents);
+ AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_SMTP, NULL,
+ SMTPGetTxDetectState, SMTPSetTxDetectState);
+
+ AppLayerParserRegisterLocalStorageFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPLocalStorageAlloc,
+ SMTPLocalStorageFree);
+
+ AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateTransactionFree);
+ AppLayerParserRegisterGetFilesFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetFiles);
+ AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetAlstateProgress);
+ AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTxCnt);
+ AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTx);
+ AppLayerParserRegisterGetStateProgressCompletionStatus(IPPROTO_TCP, ALPROTO_SMTP,
+ SMTPStateGetAlstateProgressCompletionStatus);
+ AppLayerParserRegisterTruncateFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateTruncate);
+ } else {
+ SCLogInfo("Parsed disabled for %s protocol. Protocol detection"
+ "still on.", proto_name);
+ }
+
+ SMTPSetMpmState();
+
+ SMTPConfigure();
+
+#ifdef UNITTESTS
+ AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_SMTP, SMTPParserRegisterTests);
+#endif
+ return;
+}
+
+/***************************************Unittests******************************/
+
+#ifdef UNITTESTS
+
+/*
+ * \test Test STARTTLS.
+ */
+int SMTPParserTest01(void)
+{
+ int result = 0;
+ Flow f;
+ int r = 0;
+
+ /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
+ uint8_t welcome_reply[] = {
+ 0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
+ 0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
+ 0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
+ 0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
+ 0x0d, 0x0a
+ };
+ uint32_t welcome_reply_len = sizeof(welcome_reply);
+
+ /* EHLO [192.168.0.158]<CR><LF> */
+ uint8_t request1[] = {
+ 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x5b, 0x31, 0x39,
+ 0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e,
+ 0x31, 0x35, 0x38, 0x5d, 0x0d, 0x0a
+ };
+ uint32_t request1_len = sizeof(request1);
+ /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
+ * 250-SIZE 35882577<CR><LF>
+ * 250-8BITMIME<CR><LF>
+ * 250-STARTTLS<CR><LF>
+ * 250 ENHANCEDSTATUSCODES<CR><LF>
+ */
+ uint8_t reply1[] = {
+ 0x32, 0x35, 0x30, 0x2d, 0x6d, 0x78, 0x2e, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
+ 0x6d, 0x20, 0x61, 0x74, 0x20, 0x79, 0x6f, 0x75,
+ 0x72, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
+ 0x65, 0x2c, 0x20, 0x5b, 0x31, 0x31, 0x37, 0x2e,
+ 0x31, 0x39, 0x38, 0x2e, 0x31, 0x31, 0x35, 0x2e,
+ 0x35, 0x30, 0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30,
+ 0x2d, 0x53, 0x49, 0x5a, 0x45, 0x20, 0x33, 0x35,
+ 0x38, 0x38, 0x32, 0x35, 0x37, 0x37, 0x0d, 0x0a,
+ 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49, 0x54,
+ 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35,
+ 0x30, 0x2d, 0x53, 0x54, 0x41, 0x52, 0x54, 0x54,
+ 0x4c, 0x53, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20,
+ 0x45, 0x4e, 0x48, 0x41, 0x4e, 0x43, 0x45, 0x44,
+ 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x43, 0x4f,
+ 0x44, 0x45, 0x53, 0x0d, 0x0a
+ };
+ uint32_t reply1_len = sizeof(reply1);
+
+ /* STARTTLS<CR><LF> */
+ uint8_t request2[] = {
+ 0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
+ 0x0d, 0x0a
+ };
+ uint32_t request2_len = sizeof(request2);
+ /* 220 2.0.0 Ready to start TLS<CR><LF> */
+ uint8_t reply2[] = {
+ 0x32, 0x32, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
+ 0x30, 0x20, 0x52, 0x65, 0x61, 0x64, 0x79, 0x20,
+ 0x74, 0x6f, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74,
+ 0x20, 0x54, 0x4c, 0x53, 0x0d, 0x0a
+ };
+ uint32_t reply2_len = sizeof(reply2);
+
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+
+ FLOW_INITIALIZE(&f);
+ f.protoctx = (void *)&ssn;
+ f.proto = IPPROTO_TCP;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
+ welcome_reply, welcome_reply_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ SMTPState *smtp_state = f.alstate;
+ if (smtp_state == NULL) {
+ printf("no smtp state: ");
+ goto end;
+ }
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request1, request1_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 1 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
+ reply1, reply1_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request2, request2_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 1 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
+ reply2, reply2_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
+ SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ if (!(f.flags & FLOW_NOPAYLOAD_INSPECTION) ||
+ !(ssn.flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) ||
+ !(((TcpSession *)f.protoctx)->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) ||
+ !(((TcpSession *)f.protoctx)->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
+ goto end;
+ }
+
+ result = 1;
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ FLOW_DESTROY(&f);
+ return result;
+}
+
+/**
+ * \test Test multiple DATA commands(full mail transactions).
+ */
+int SMTPParserTest02(void)
+{
+ int result = 0;
+ Flow f;
+ int r = 0;
+
+ /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
+ uint8_t welcome_reply[] = {
+ 0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
+ 0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
+ 0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
+ 0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
+ 0x0d, 0x0a
+ };
+ uint32_t welcome_reply_len = sizeof(welcome_reply);
+
+ /* EHLO boo.com<CR><LF> */
+ uint8_t request1[] = {
+ 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
+ };
+ uint32_t request1_len = sizeof(request1);
+ /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
+ * 250-SIZE 35882577<CR><LF>
+ * 250-8BITMIME<CR><LF>
+ * 250-STARTTLS<CR><LF>
+ * 250 ENHANCEDSTATUSCODES<CR><LF>
+ */
+ uint8_t reply1[] = {
+ 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
+ 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
+ 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
+ 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
+ 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
+ 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
+ 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
+ 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
+ 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
+ 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
+ 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
+ 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
+ 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
+ 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
+ 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
+ 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
+ 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
+ };
+ uint32_t reply1_len = sizeof(reply1);
+
+ /* MAIL FROM:asdff@asdf.com<CR><LF> */
+ uint8_t request2[] = {
+ 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
+ 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
+ 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x0d, 0x0a
+ };
+ uint32_t request2_len = sizeof(request2);
+ /* 250 2.1.0 Ok<CR><LF> */
+ uint8_t reply2[] = {
+ 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
+ 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
+ };
+ uint32_t reply2_len = sizeof(reply2);
+
+ /* RCPT TO:bimbs@gmail.com<CR><LF> */
+ uint8_t request3[] = {
+ 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
+ 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
+ 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
+ 0x0a
+ };
+ uint32_t request3_len = sizeof(request3);
+ /* 250 2.1.5 Ok<CR><LF> */
+ uint8_t reply3[] = {
+ 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
+ 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
+ };
+ uint32_t reply3_len = sizeof(reply3);
+
+ /* DATA<CR><LF> */
+ uint8_t request4[] = {
+ 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
+ };
+ uint32_t request4_len = sizeof(request4);
+ /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
+ uint8_t reply4[] = {
+ 0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
+ 0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
+ 0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
+ 0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
+ 0x4c, 0x46, 0x3e, 0x0d, 0x0a
+ };
+ uint32_t reply4_len = sizeof(reply4);
+
+ /* FROM:asdff@asdf.com<CR><LF> */
+ uint8_t request5_1[] = {
+ 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
+ 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
+ 0x63, 0x6f, 0x6d, 0x0d, 0x0a
+ };
+ uint32_t request5_1_len = sizeof(request5_1);
+ /* TO:bimbs@gmail.com<CR><LF> */
+ uint8_t request5_2[] = {
+ 0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73,
+ 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x0d, 0x0a
+ };
+ uint32_t request5_2_len = sizeof(request5_2);
+ /* <CR><LF> */
+ uint8_t request5_3[] = {
+ 0x0d, 0x0a
+ };
+ uint32_t request5_3_len = sizeof(request5_3);
+ /* this is test mail1<CR><LF> */
+ uint8_t request5_4[] = {
+ 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
+ 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x69,
+ 0x6c, 0x31, 0x0d, 0x0a
+ };
+ uint32_t request5_4_len = sizeof(request5_4);
+ /* .<CR><LF> */
+ uint8_t request5_5[] = {
+ 0x2e, 0x0d, 0x0a
+ };
+ uint32_t request5_5_len = sizeof(request5_5);
+ /* 250 2.0.0 Ok: queued as 6A1AF20BF2<CR><LF> */
+ uint8_t reply5[] = {
+ 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
+ 0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
+ 0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
+ 0x36, 0x41, 0x31, 0x41, 0x46, 0x32, 0x30, 0x42,
+ 0x46, 0x32, 0x0d, 0x0a
+ };
+ uint32_t reply5_len = sizeof(reply5);
+
+ /* MAIL FROM:asdfg@asdf.com<CR><LF> */
+ uint8_t request6[] = {
+ 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
+ 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x67, 0x40,
+ 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x0d, 0x0a
+ };
+ uint32_t request6_len = sizeof(request6);
+ /* 250 2.1.0 Ok<CR><LF> */
+ uint8_t reply6[] = {
+ 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
+ 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
+ };
+ uint32_t reply6_len = sizeof(reply6);
+
+ /* RCPT TO:bimbs@gmail.com<CR><LF> */
+ uint8_t request7[] = {
+ 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
+ 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
+ 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
+ 0x0a
+ };
+ uint32_t request7_len = sizeof(request7);
+ /* 250 2.1.5 Ok<CR><LF> */
+ uint8_t reply7[] = {
+ 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
+ 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
+ };
+ uint32_t reply7_len = sizeof(reply7);
+
+ /* DATA<CR><LF> */
+ uint8_t request8[] = {
+ 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
+ };
+ uint32_t request8_len = sizeof(request8);
+ /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
+ uint8_t reply8[] = {
+ 0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
+ 0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
+ 0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
+ 0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
+ 0x4c, 0x46, 0x3e, 0x0d, 0x0a
+ };
+ uint32_t reply8_len = sizeof(reply8);
+
+ /* FROM:asdfg@gmail.com<CR><LF> */
+ uint8_t request9_1[] = {
+ 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
+ 0x66, 0x67, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
+ };
+ uint32_t request9_1_len = sizeof(request9_1);
+ /* TO:bimbs@gmail.com<CR><LF> */
+ uint8_t request9_2[] = {
+ 0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73,
+ 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x0d, 0x0a
+ };
+ uint32_t request9_2_len = sizeof(request9_2);
+ /* <CR><LF> */
+ uint8_t request9_3[] = {
+ 0x0d, 0x0a
+ };
+ uint32_t request9_3_len = sizeof(request9_3);
+ /* this is test mail2<CR><LF> */
+ uint8_t request9_4[] = {
+ 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
+ 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x69,
+ 0x6c, 0x32, 0x0d, 0x0a
+ };
+ uint32_t request9_4_len = sizeof(request9_4);
+ /* .<CR><LF> */
+ uint8_t request9_5[] = {
+ 0x2e, 0x0d, 0x0a
+ };
+ uint32_t request9_5_len = sizeof(request9_5);
+ /* 250 2.0.0 Ok: queued as 28CFF20BF2<CR><LF> */
+ uint8_t reply9[] = {
+ 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
+ 0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
+ 0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
+ 0x32, 0x38, 0x43, 0x46, 0x46, 0x32, 0x30, 0x42,
+ 0x46, 0x32, 0x0d, 0x0a
+ };
+ uint32_t reply9_len = sizeof(reply9);
+
+ /* QUIT<CR><LF> */
+ uint8_t request10[] = {
+ 0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
+ };
+ uint32_t request10_len = sizeof(request10);
+ /* 221 2.0.0 Bye<CR><LF> */
+ uint8_t reply10[] = {
+ 0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
+ 0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
+ };
+ uint32_t reply10_len = sizeof(reply10);
+
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+
+ FLOW_INITIALIZE(&f);
+ f.protoctx = (void *)&ssn;
+ f.proto = IPPROTO_TCP;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
+ welcome_reply, welcome_reply_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ SMTPState *smtp_state = f.alstate;
+ if (smtp_state == NULL) {
+ printf("no smtp state: ");
+ goto end;
+ }
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request1, request1_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 1 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
+ reply1, reply1_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request2, request2_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 1 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
+ reply2, reply2_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request3, request3_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 1 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
+ reply3, reply3_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request4, request4_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 1 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
+ reply4, reply4_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
+ SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request5_1, request5_1_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
+ SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
+
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request5_2, request5_2_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
+ SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
+
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request5_3, request5_3_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
+ SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
+
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request5_4, request5_4_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
+ SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
+
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request5_5, request5_5_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 1 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
+ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
+ reply5, reply5_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request6, request6_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 1 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
+ reply6, reply6_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request7, request7_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 1 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
+ reply7, reply7_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request8, request8_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 1 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
+ reply8, reply8_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
+ SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request9_1, request9_1_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
+ SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
+
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request9_2, request9_2_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
+ SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
+
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request9_3, request9_3_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
+ SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
+
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request9_4, request9_4_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
+ SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
+
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request9_5, request9_5_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 1 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
+ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
+ reply9, reply9_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request10, request10_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 1 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
+ reply10, reply10_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ result = 1;
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ FLOW_DESTROY(&f);
+ return result;
+}
+
+/**
+ * \test Testing parsing pipelined commands.
+ */
+int SMTPParserTest03(void)
+{
+ int result = 0;
+ Flow f;
+ int r = 0;
+
+ /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
+ uint8_t welcome_reply[] = {
+ 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
+ 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
+ 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
+ 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
+ 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
+ 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
+ };
+ uint32_t welcome_reply_len = sizeof(welcome_reply);
+
+ /* EHLO boo.com<CR><LF> */
+ uint8_t request1[] = {
+ 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x0a
+ };
+ uint32_t request1_len = sizeof(request1);
+ /* 250-poona_slack_vm1.localdomain<CR><LF>
+ * 250-PIPELINING<CR><LF>
+ * 250-SIZE 10240000<CR><LF>
+ * 250-VRFY<CR><LF>
+ * 250-ETRN<CR><LF>
+ * 250-ENHANCEDSTATUSCODES<CR><LF>
+ * 250-8BITMIME<CR><LF>
+ * 250 DSN<CR><LF>
+ */
+ uint8_t reply1[] = {
+ 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
+ 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
+ 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
+ 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
+ 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
+ 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
+ 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
+ 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
+ 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
+ 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
+ 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
+ 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
+ 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
+ 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
+ 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
+ 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
+ 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
+ };
+ uint32_t reply1_len = sizeof(reply1);
+
+ /* MAIL FROM:pbsf@asdfs.com<CR><LF>
+ * RCPT TO:pbsf@asdfs.com<CR><LF>
+ * DATA<CR><LF>
+ */
+ uint8_t request2[] = {
+ 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
+ 0x4d, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
+ 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x0d, 0x0a, 0x52, 0x43, 0x50, 0x54, 0x20, 0x54,
+ 0x4f, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
+ 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x0d, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
+ };
+ uint32_t request2_len = sizeof(request2);
+ /* 250 2.1.0 Ok<CR><LF>
+ * 250 2.1.5 Ok<CR><LF>
+ * 354 End data with <CR><LF>.<CR><LF>|<CR><LF>|
+ */
+ uint8_t reply2[] = {
+ 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
+ 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a, 0x32, 0x35,
+ 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, 0x35, 0x20,
+ 0x4f, 0x6b, 0x0d, 0x0a, 0x33, 0x35, 0x34, 0x20,
+ 0x45, 0x6e, 0x64, 0x20, 0x64, 0x61, 0x74, 0x61,
+ 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x3c, 0x43,
+ 0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x2e, 0x3c,
+ 0x43, 0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x0d,
+ 0x0a
+ };
+ uint32_t reply2_len = sizeof(reply2);
+
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+
+ FLOW_INITIALIZE(&f);
+ f.protoctx = (void *)&ssn;
+ f.proto = IPPROTO_TCP;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
+ welcome_reply, welcome_reply_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ SMTPState *smtp_state = f.alstate;
+ if (smtp_state == NULL) {
+ printf("no smtp state: ");
+ goto end;
+ }
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request1, request1_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 1 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
+ reply1, reply1_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request2, request2_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 3 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
+ smtp_state->cmds[1] != SMTP_COMMAND_OTHER_CMD ||
+ smtp_state->cmds[2] != SMTP_COMMAND_DATA ||
+ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
+ reply2, reply2_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
+ SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ result = 1;
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ FLOW_DESTROY(&f);
+ return result;
+}
+
+/*
+ * \test Test smtp with just <LF> delimter instead of <CR><LF>.
+ */
+int SMTPParserTest04(void)
+{
+ int result = 0;
+ Flow f;
+ int r = 0;
+
+ /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
+ uint8_t welcome_reply[] = {
+ 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
+ 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
+ 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
+ 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
+ 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
+ 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
+ };
+ uint32_t welcome_reply_len = sizeof(welcome_reply);
+
+ /* EHLO boo.com<CR><LF> */
+ uint8_t request1[] = {
+ 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
+ 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
+ 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
+ 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
+ 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
+ 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
+ };
+ uint32_t request1_len = sizeof(request1);
+
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+
+ FLOW_INITIALIZE(&f);
+ f.protoctx = (void *)&ssn;
+ f.proto = IPPROTO_TCP;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
+ welcome_reply, welcome_reply_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ SMTPState *smtp_state = f.alstate;
+ if (smtp_state == NULL) {
+ printf("no smtp state: ");
+ goto end;
+ }
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request1, request1_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 1 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ result = 1;
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ FLOW_DESTROY(&f);
+ return result;
+}
+
+/*
+ * \test Test STARTTLS fail.
+ */
+int SMTPParserTest05(void)
+{
+ int result = 0;
+ Flow f;
+ int r = 0;
+
+ /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
+ uint8_t welcome_reply[] = {
+ 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
+ 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
+ 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
+ 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
+ 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
+ 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
+ };
+ uint32_t welcome_reply_len = sizeof(welcome_reply);
+
+ /* EHLO boo.com<CR><LF> */
+ uint8_t request1[] = {
+ 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
+ };
+ uint32_t request1_len = sizeof(request1);
+ /* 250-poona_slack_vm1.localdomain<CR><LF>
+ * 250-PIPELINING<CR><LF>
+ * 250-SIZE 10240000<CR><LF>
+ * 250-VRFY<CR><LF>
+ * 250-ETRN<CR><LF>
+ * 250-ENHANCEDSTATUSCODES<CR><LF>
+ * 250-8BITMIME<CR><LF>
+ * 250 DSN<CR><LF>
+ */
+ uint8_t reply1[] = {
+ 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
+ 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
+ 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
+ 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
+ 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
+ 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
+ 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
+ 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
+ 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
+ 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
+ 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
+ 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
+ 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
+ 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
+ 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
+ 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
+ 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
+ };
+ uint32_t reply1_len = sizeof(reply1);
+
+ /* STARTTLS<CR><LF> */
+ uint8_t request2[] = {
+ 0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
+ 0x0d, 0x0a
+ };
+ uint32_t request2_len = sizeof(request2);
+ /* 502 5.5.2 Error: command not recognized<CR><LF> */
+ uint8_t reply2[] = {
+ 0x35, 0x30, 0x32, 0x20, 0x35, 0x2e, 0x35, 0x2e,
+ 0x32, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x3a,
+ 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
+ 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x63,
+ 0x6f, 0x67, 0x6e, 0x69, 0x7a, 0x65, 0x64, 0x0d,
+ 0x0a
+ };
+ uint32_t reply2_len = sizeof(reply2);
+
+ /* QUIT<CR><LF> */
+ uint8_t request3[] = {
+ 0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
+
+ };
+ uint32_t request3_len = sizeof(request3);
+ /* 221 2.0.0 Bye<CR><LF> */
+ uint8_t reply3[] = {
+ 0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
+ 0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
+ };
+ uint32_t reply3_len = sizeof(reply3);
+
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+
+ FLOW_INITIALIZE(&f);
+ f.protoctx = (void *)&ssn;
+ f.proto = IPPROTO_TCP;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
+ welcome_reply, welcome_reply_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ SMTPState *smtp_state = f.alstate;
+ if (smtp_state == NULL) {
+ printf("no smtp state: ");
+ goto end;
+ }
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request1, request1_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 1 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
+ reply1, reply1_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request2, request2_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 1 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
+ reply2, reply2_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ if ((f.flags & FLOW_NOPAYLOAD_INSPECTION) ||
+ (ssn.flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) ||
+ (((TcpSession *)f.protoctx)->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) ||
+ (((TcpSession *)f.protoctx)->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request3, request3_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 1 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
+ reply3, reply3_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ result = 1;
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ FLOW_DESTROY(&f);
+ return result;
+}
+
+/**
+ * \test Test multiple DATA commands(full mail transactions).
+ */
+int SMTPParserTest06(void)
+{
+ int result = 0;
+ Flow f;
+ int r = 0;
+
+ uint8_t welcome_reply[] = {
+ 0x32, 0x32, 0x30, 0x20, 0x62, 0x61, 0x79, 0x30,
+ 0x2d, 0x6d, 0x63, 0x36, 0x2d, 0x66, 0x31, 0x30,
+ 0x2e, 0x62, 0x61, 0x79, 0x30, 0x2e, 0x68, 0x6f,
+ 0x74, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f,
+ 0x6d, 0x20, 0x53, 0x65, 0x6e, 0x64, 0x69, 0x6e,
+ 0x67, 0x20, 0x75, 0x6e, 0x73, 0x6f, 0x6c, 0x69,
+ 0x63, 0x69, 0x74, 0x65, 0x64, 0x20, 0x63, 0x6f,
+ 0x6d, 0x6d, 0x65, 0x72, 0x63, 0x69, 0x61, 0x6c,
+ 0x20, 0x6f, 0x72, 0x20, 0x62, 0x75, 0x6c, 0x6b,
+ 0x20, 0x65, 0x2d, 0x6d, 0x61, 0x69, 0x6c, 0x20,
+ 0x74, 0x6f, 0x20, 0x4d, 0x69, 0x63, 0x72, 0x6f,
+ 0x73, 0x6f, 0x66, 0x74, 0x27, 0x73, 0x20, 0x63,
+ 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x20,
+ 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20,
+ 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x68, 0x69,
+ 0x62, 0x69, 0x74, 0x65, 0x64, 0x2e, 0x20, 0x4f,
+ 0x74, 0x68, 0x65, 0x72, 0x20, 0x72, 0x65, 0x73,
+ 0x74, 0x72, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e,
+ 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x66, 0x6f,
+ 0x75, 0x6e, 0x64, 0x20, 0x61, 0x74, 0x20, 0x68,
+ 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x72,
+ 0x69, 0x76, 0x61, 0x63, 0x79, 0x2e, 0x6d, 0x73,
+ 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x41, 0x6e,
+ 0x74, 0x69, 0x2d, 0x73, 0x70, 0x61, 0x6d, 0x2f,
+ 0x2e, 0x20, 0x56, 0x69, 0x6f, 0x6c, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x77, 0x69, 0x6c,
+ 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74,
+ 0x20, 0x69, 0x6e, 0x20, 0x75, 0x73, 0x65, 0x20,
+ 0x6f, 0x66, 0x20, 0x65, 0x71, 0x75, 0x69, 0x70,
+ 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x63,
+ 0x61, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20,
+ 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e,
+ 0x69, 0x61, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6f,
+ 0x74, 0x68, 0x65, 0x72, 0x20, 0x73, 0x74, 0x61,
+ 0x74, 0x65, 0x73, 0x2e, 0x20, 0x46, 0x72, 0x69,
+ 0x2c, 0x20, 0x31, 0x36, 0x20, 0x46, 0x65, 0x62,
+ 0x20, 0x32, 0x30, 0x30, 0x37, 0x20, 0x30, 0x35,
+ 0x3a, 0x30, 0x33, 0x3a, 0x32, 0x33, 0x20, 0x2d,
+ 0x30, 0x38, 0x30, 0x30, 0x20, 0x0d, 0x0a
+ };
+ uint32_t welcome_reply_len = sizeof(welcome_reply);
+
+ uint8_t request1[] = {
+ 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x45, 0x58, 0x43,
+ 0x48, 0x41, 0x4e, 0x47, 0x45, 0x32, 0x2e, 0x63,
+ 0x67, 0x63, 0x65, 0x6e, 0x74, 0x2e, 0x6d, 0x69,
+ 0x61, 0x6d, 0x69, 0x2e, 0x65, 0x64, 0x75, 0x0d,
+ 0x0a
+ };
+ uint32_t request1_len = sizeof(request1);
+
+ uint8_t reply1[] = {
+ 0x32, 0x35, 0x30, 0x2d, 0x62, 0x61, 0x79, 0x30,
+ 0x2d, 0x6d, 0x63, 0x36, 0x2d, 0x66, 0x31, 0x30,
+ 0x2e, 0x62, 0x61, 0x79, 0x30, 0x2e, 0x68, 0x6f,
+ 0x74, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f,
+ 0x6d, 0x20, 0x28, 0x33, 0x2e, 0x33, 0x2e, 0x31,
+ 0x2e, 0x34, 0x29, 0x20, 0x48, 0x65, 0x6c, 0x6c,
+ 0x6f, 0x20, 0x5b, 0x31, 0x32, 0x39, 0x2e, 0x31,
+ 0x37, 0x31, 0x2e, 0x33, 0x32, 0x2e, 0x35, 0x39,
+ 0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53,
+ 0x49, 0x5a, 0x45, 0x20, 0x32, 0x39, 0x36, 0x39,
+ 0x36, 0x30, 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35,
+ 0x30, 0x2d, 0x50, 0x49, 0x50, 0x45, 0x4c, 0x49,
+ 0x4e, 0x49, 0x4e, 0x47, 0x0d, 0x0a, 0x32, 0x35,
+ 0x30, 0x2d, 0x38, 0x62, 0x69, 0x74, 0x6d, 0x69,
+ 0x6d, 0x65, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
+ 0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x4d, 0x49,
+ 0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
+ 0x43, 0x48, 0x55, 0x4e, 0x4b, 0x49, 0x4e, 0x47,
+ 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x41, 0x55,
+ 0x54, 0x48, 0x20, 0x4c, 0x4f, 0x47, 0x49, 0x4e,
+ 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x41, 0x55,
+ 0x54, 0x48, 0x3d, 0x4c, 0x4f, 0x47, 0x49, 0x4e,
+ 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20, 0x4f, 0x4b,
+ 0x0d, 0x0a
+ };
+ uint32_t reply1_len = sizeof(reply1);
+
+ /* MAIL FROM:asdff@asdf.com<CR><LF> */
+ uint8_t request2[] = {
+ 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
+ 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
+ 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x0d, 0x0a
+ };
+ uint32_t request2_len = sizeof(request2);
+ /* 250 2.1.0 Ok<CR><LF> */
+ uint8_t reply2[] = {
+ 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
+ 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
+ };
+ uint32_t reply2_len = sizeof(reply2);
+
+ /* RCPT TO:bimbs@gmail.com<CR><LF> */
+ uint8_t request3[] = {
+ 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
+ 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
+ 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
+ 0x0a
+ };
+ uint32_t request3_len = sizeof(request3);
+ /* 250 2.1.5 Ok<CR><LF> */
+ uint8_t reply3[] = {
+ 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
+ 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
+ };
+ uint32_t reply3_len = sizeof(reply3);
+
+ /* BDAT 51<CR><LF> */
+ uint8_t request4[] = {
+ 0x42, 0x44, 0x41, 0x54, 0x20, 0x35, 0x31, 0x0d,
+ 0x0a,
+ };
+ uint32_t request4_len = sizeof(request4);
+
+ uint8_t request5[] = {
+ 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
+ 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
+ 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
+ 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x0d, 0x0a,
+ };
+ uint32_t request5_len = sizeof(request5);
+
+ uint8_t request6[] = {
+ 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
+ 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
+ 0x66, 0x0d, 0x0a,
+ };
+ uint32_t request6_len = sizeof(request6);
+
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+
+ FLOW_INITIALIZE(&f);
+ f.protoctx = (void *)&ssn;
+ f.proto = IPPROTO_TCP;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
+ welcome_reply, welcome_reply_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ SMTPState *smtp_state = f.alstate;
+ if (smtp_state == NULL) {
+ printf("no smtp state: ");
+ goto end;
+ }
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request1, request1_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 1 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
+ reply1, reply1_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request2, request2_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 1 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
+ reply2, reply2_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request3, request3_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 1 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
+ reply3, reply3_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request4, request4_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 1 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->cmds[0] != SMTP_COMMAND_BDAT ||
+ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
+ SMTP_PARSER_STATE_COMMAND_DATA_MODE) ||
+ smtp_state->bdat_chunk_len != 51 ||
+ smtp_state->bdat_chunk_idx != 0) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request5, request5_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 1 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
+ SMTP_PARSER_STATE_COMMAND_DATA_MODE) ||
+ smtp_state->bdat_chunk_len != 51 ||
+ smtp_state->bdat_chunk_idx != 32) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request6, request6_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 1 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN ||
+ smtp_state->bdat_chunk_len != 51 ||
+ smtp_state->bdat_chunk_idx != 51) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ result = 1;
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ FLOW_DESTROY(&f);
+ return result;
+}
+
+/*
+ * \test Test retrieving lines when frag'ed.
+ */
+int SMTPParserTest07(void)
+{
+ int result = 0;
+ Flow f;
+ int r = 0;
+
+ const char *request1_str = "EHLO boo.com";
+ /* EHLO boo.com<CR> */
+ uint8_t request1_1[] = {
+ 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
+ };
+ int32_t request1_1_len = sizeof(request1_1);
+
+ /* <LF> */
+ uint8_t request1_2[] = {
+ 0x0a
+ };
+ int32_t request1_2_len = sizeof(request1_2);
+
+ /* EHLO boo.com<CR><LF> */
+ uint8_t request2[] = {
+ 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
+ };
+ int32_t request2_len = sizeof(request2);
+
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+
+ FLOW_INITIALIZE(&f);
+ f.protoctx = (void *)&ssn;
+ f.proto = IPPROTO_TCP;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request1_1, request1_1_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ SMTPState *smtp_state = f.alstate;
+ if (smtp_state == NULL) {
+ printf("no smtp state: ");
+ goto end;
+ }
+ if (smtp_state->current_line != NULL ||
+ smtp_state->current_line_len != 0 ||
+ smtp_state->ts_current_line_db != 1 ||
+ smtp_state->ts_db == NULL ||
+ smtp_state->ts_db_len != request1_1_len ||
+ memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request1_2, request1_2_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->ts_current_line_db != 1 ||
+ smtp_state->ts_db == NULL ||
+ smtp_state->ts_db_len != (int32_t)strlen(request1_str) ||
+ memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 ||
+ smtp_state->current_line != smtp_state->ts_db ||
+ smtp_state->current_line_len != smtp_state->ts_db_len) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request2, request2_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->ts_current_line_db != 0 ||
+ smtp_state->ts_db != NULL ||
+ smtp_state->ts_db_len != 0 ||
+ smtp_state->current_line == NULL ||
+ smtp_state->current_line_len != (int32_t)strlen(request1_str) ||
+ memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ result = 1;
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ FLOW_DESTROY(&f);
+ return result;
+}
+
+/*
+ * \test Test retrieving lines when frag'ed.
+ */
+int SMTPParserTest08(void)
+{
+ int result = 0;
+ Flow f;
+ int r = 0;
+
+ const char *request1_str = "EHLO boo.com";
+ /* EHLO boo.com */
+ uint8_t request1_1[] = {
+ 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
+ 0x2e, 0x63, 0x6f, 0x6d,
+ };
+ int32_t request1_1_len = sizeof(request1_1);
+
+ /* <CR><LF> */
+ uint8_t request1_2[] = {
+ 0x0d, 0x0a
+ };
+ int32_t request1_2_len = sizeof(request1_2);
+
+ /* EHLO boo.com<CR><LF> */
+ uint8_t request2[] = {
+ 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
+ };
+ int32_t request2_len = sizeof(request2);
+
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+
+ FLOW_INITIALIZE(&f);
+ f.protoctx = (void *)&ssn;
+ f.proto = IPPROTO_TCP;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request1_1, request1_1_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ SMTPState *smtp_state = f.alstate;
+ if (smtp_state == NULL) {
+ printf("no smtp state: ");
+ goto end;
+ }
+ if (smtp_state->current_line != NULL ||
+ smtp_state->current_line_len != 0 ||
+ smtp_state->ts_current_line_db != 1 ||
+ smtp_state->ts_db == NULL ||
+ smtp_state->ts_db_len != request1_1_len ||
+ memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request1_2, request1_2_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->ts_current_line_db != 1 ||
+ smtp_state->ts_db == NULL ||
+ smtp_state->ts_db_len != (int32_t)strlen(request1_str) ||
+ memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 ||
+ smtp_state->current_line != smtp_state->ts_db ||
+ smtp_state->current_line_len != smtp_state->ts_db_len) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request2, request2_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->ts_current_line_db != 0 ||
+ smtp_state->ts_db != NULL ||
+ smtp_state->ts_db_len != 0 ||
+ smtp_state->current_line == NULL ||
+ smtp_state->current_line_len != (int32_t)strlen(request1_str) ||
+ memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ result = 1;
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ FLOW_DESTROY(&f);
+ return result;
+}
+
+/*
+ * \test Test retrieving lines when frag'ed.
+ */
+int SMTPParserTest09(void)
+{
+ int result = 0;
+ Flow f;
+ int r = 0;
+
+ const char *request1_str = "EHLO boo.com";
+ /* EHLO boo. */
+ uint8_t request1_1[] = {
+ 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
+ 0x2e,
+ };
+ int32_t request1_1_len = sizeof(request1_1);
+
+ /* com<CR><LF> */
+ uint8_t request1_2[] = {
+ 0x63, 0x6f, 0x6d, 0x0d, 0x0a
+ };
+ int32_t request1_2_len = sizeof(request1_2);
+
+ /* EHLO boo.com<CR><LF> */
+ uint8_t request2[] = {
+ 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
+ };
+ int32_t request2_len = sizeof(request2);
+
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+
+ FLOW_INITIALIZE(&f);
+ f.protoctx = (void *)&ssn;
+ f.proto = IPPROTO_TCP;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request1_1, request1_1_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ SMTPState *smtp_state = f.alstate;
+ if (smtp_state == NULL) {
+ printf("no smtp state: ");
+ goto end;
+ }
+ if (smtp_state->current_line != NULL ||
+ smtp_state->current_line_len != 0 ||
+ smtp_state->ts_current_line_db != 1 ||
+ smtp_state->ts_db == NULL ||
+ smtp_state->ts_db_len != request1_1_len ||
+ memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request1_2, request1_2_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->ts_current_line_db != 1 ||
+ smtp_state->ts_db == NULL ||
+ smtp_state->ts_db_len != (int32_t)strlen(request1_str) ||
+ memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 ||
+ smtp_state->current_line != smtp_state->ts_db ||
+ smtp_state->current_line_len != smtp_state->ts_db_len) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request2, request2_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->ts_current_line_db != 0 ||
+ smtp_state->ts_db != NULL ||
+ smtp_state->ts_db_len != 0 ||
+ smtp_state->current_line == NULL ||
+ smtp_state->current_line_len != (int32_t)strlen(request1_str) ||
+ memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ result = 1;
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ FLOW_DESTROY(&f);
+ return result;
+}
+
+/*
+ * \test Test retrieving lines when frag'ed.
+ */
+int SMTPParserTest10(void)
+{
+ int result = 0;
+ Flow f;
+ int r = 0;
+
+ const char *request1_str = "";
+ /* EHLO boo. */
+ uint8_t request1_1[] = {
+ 0x0d,
+ };
+ int32_t request1_1_len = sizeof(request1_1);
+
+ /* com<CR><LF> */
+ uint8_t request1_2[] = {
+ 0x0a,
+ };
+ int32_t request1_2_len = sizeof(request1_2);
+
+ const char *request2_str = "EHLO boo.com";
+ /* EHLO boo.com<CR><LF> */
+ uint8_t request2[] = {
+ 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
+ };
+ int32_t request2_len = sizeof(request2);
+
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+
+ FLOW_INITIALIZE(&f);
+ f.protoctx = (void *)&ssn;
+ f.proto = IPPROTO_TCP;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request1_1, request1_1_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ SMTPState *smtp_state = f.alstate;
+ if (smtp_state == NULL) {
+ printf("no smtp state: ");
+ goto end;
+ }
+ if (smtp_state->current_line != NULL ||
+ smtp_state->current_line_len != 0 ||
+ smtp_state->ts_current_line_db != 1 ||
+ smtp_state->ts_db == NULL ||
+ smtp_state->ts_db_len != request1_1_len ||
+ memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request1_2, request1_2_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->ts_current_line_db != 1 ||
+ smtp_state->ts_db == NULL ||
+ smtp_state->ts_db_len != (int32_t)strlen(request1_str) ||
+ memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 ||
+ smtp_state->current_line != smtp_state->ts_db ||
+ smtp_state->current_line_len != smtp_state->ts_db_len) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request2, request2_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->ts_current_line_db != 0 ||
+ smtp_state->ts_db != NULL ||
+ smtp_state->ts_db_len != 0 ||
+ smtp_state->current_line == NULL ||
+ smtp_state->current_line_len != (int32_t)strlen(request2_str) ||
+ memcmp(smtp_state->current_line, request2_str, strlen(request2_str)) != 0) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ result = 1;
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ FLOW_DESTROY(&f);
+ return result;
+}
+
+/*
+ * \test Test retrieving lines when frag'ed.
+ */
+int SMTPParserTest11(void)
+{
+ int result = 0;
+ Flow f;
+ int r = 0;
+
+ const char *request1_str = "";
+ /* EHLO boo. */
+ uint8_t request1[] = {
+ 0x0a,
+ };
+ int32_t request1_len = sizeof(request1);
+
+ const char *request2_str = "EHLO boo.com";
+ /* EHLO boo.com<CR><LF> */
+ uint8_t request2[] = {
+ 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
+ };
+ int32_t request2_len = sizeof(request2);
+
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+
+ FLOW_INITIALIZE(&f);
+ f.protoctx = (void *)&ssn;
+ f.proto = IPPROTO_TCP;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request1, request1_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ SMTPState *smtp_state = f.alstate;
+ if (smtp_state == NULL) {
+ printf("no smtp state: ");
+ goto end;
+ }
+ if (smtp_state->current_line == NULL ||
+ smtp_state->current_line_len != 0 ||
+ smtp_state->ts_current_line_db == 1 ||
+ smtp_state->ts_db != NULL ||
+ smtp_state->ts_db_len != 0 ||
+ memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request2, request2_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->ts_current_line_db != 0 ||
+ smtp_state->ts_db != NULL ||
+ smtp_state->ts_db_len != 0 ||
+ smtp_state->current_line == NULL ||
+ smtp_state->current_line_len != (int32_t)strlen(request2_str) ||
+ memcmp(smtp_state->current_line, request2_str, strlen(request2_str)) != 0) {
+ printf("smtp parser in inconsistent state\n");
+ goto end;
+ }
+
+ result = 1;
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ FLOW_DESTROY(&f);
+ return result;
+}
+
+int SMTPParserTest12(void)
+{
+ int result = 0;
+ Signature *s = NULL;
+ ThreadVars th_v;
+ Packet *p = NULL;
+ Flow f;
+ TcpSession ssn;
+ DetectEngineThreadCtx *det_ctx = NULL;
+ DetectEngineCtx *de_ctx = NULL;
+ SMTPState *smtp_state = NULL;
+ int r = 0;
+
+ /* EHLO boo.com<CR><LF> */
+ uint8_t request1[] = {
+ 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
+ };
+ int32_t request1_len = sizeof(request1);
+
+ /* 388<CR><LF>
+ */
+ uint8_t reply1[] = {
+ 0x31, 0x38, 0x38, 0x0d, 0x0a,
+ };
+ uint32_t reply1_len = sizeof(reply1);
+
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&th_v, 0, sizeof(th_v));
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+
+ p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
+
+ FLOW_INITIALIZE(&f);
+ f.protoctx = (void *)&ssn;
+ f.proto = IPPROTO_TCP;
+ p->flow = &f;
+ p->flowflags |= FLOW_PKT_TOSERVER;
+ p->flowflags |= FLOW_PKT_ESTABLISHED;
+ p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
+ f.alproto = ALPROTO_SMTP;
+
+ StreamTcpInitConfig(TRUE);
+
+ de_ctx = DetectEngineCtxInit();
+ if (de_ctx == NULL)
+ goto end;
+
+ de_ctx->flags |= DE_QUIET;
+
+ s = DetectEngineAppendSig(de_ctx,"alert tcp any any -> any any "
+ "(msg:\"SMTP event handling\"; "
+ "app-layer-event: smtp.invalid_reply; "
+ "sid:1;)");
+ if (s == NULL)
+ goto end;
+
+ SigGroupBuild(de_ctx);
+ DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER | STREAM_START,
+ request1, request1_len);
+ if (r != 0) {
+ printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ smtp_state = f.alstate;
+ if (smtp_state == NULL) {
+ printf("no smtp state: ");
+ goto end;
+ }
+
+ /* do detect */
+ SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
+
+ if (PacketAlertCheck(p, 1)) {
+ printf("sid 1 matched. It shouldn't match: ");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT | STREAM_TOCLIENT,
+ reply1, reply1_len);
+ if (r == 0) {
+ printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ /* do detect */
+ SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
+
+ if (!PacketAlertCheck(p, 1)) {
+ printf("sid 1 didn't match. Should have matched: ");
+ goto end;
+ }
+
+ result = 1;
+
+end:
+ SigGroupCleanup(de_ctx);
+ SigCleanSignatures(de_ctx);
+
+ DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
+ DetectEngineCtxFree(de_ctx);
+
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ FLOW_DESTROY(&f);
+ UTHFreePackets(&p, 1);
+ return result;
+}
+
+int SMTPParserTest13(void)
+{
+ int result = 0;
+ Signature *s = NULL;
+ ThreadVars th_v;
+ Packet *p = NULL;
+ Flow f;
+ TcpSession ssn;
+ DetectEngineThreadCtx *det_ctx = NULL;
+ DetectEngineCtx *de_ctx = NULL;
+ SMTPState *smtp_state = NULL;
+ int r = 0;
+
+ /* EHLO boo.com<CR><LF> */
+ uint8_t request1[] = {
+ 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
+ };
+ int32_t request1_len = sizeof(request1);
+
+ /* 250<CR><LF>
+ */
+ uint8_t reply1[] = {
+ 0x32, 0x35, 0x30, 0x0d, 0x0a,
+ };
+ uint32_t reply1_len = sizeof(reply1);
+
+ /* MAIL FROM:pbsf@asdfs.com<CR><LF>
+ * RCPT TO:pbsf@asdfs.com<CR><LF>
+ * DATA<CR><LF>
+ * STARTTLS<CR><LF>
+ */
+ uint8_t request2[] = {
+ 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
+ 0x4d, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
+ 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x0d, 0x0a, 0x52, 0x43, 0x50, 0x54, 0x20, 0x54,
+ 0x4f, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
+ 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x0d, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a,
+ 0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
+ 0x0d, 0x0a
+ };
+ uint32_t request2_len = sizeof(request2);
+
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&th_v, 0, sizeof(th_v));
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+
+ p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
+
+ FLOW_INITIALIZE(&f);
+ f.protoctx = (void *)&ssn;
+ f.proto = IPPROTO_TCP;
+ p->flow = &f;
+ p->flowflags |= FLOW_PKT_TOSERVER;
+ p->flowflags |= FLOW_PKT_ESTABLISHED;
+ p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
+ f.alproto = ALPROTO_SMTP;
+
+ StreamTcpInitConfig(TRUE);
+
+ de_ctx = DetectEngineCtxInit();
+ if (de_ctx == NULL)
+ goto end;
+
+ de_ctx->flags |= DE_QUIET;
+
+ s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
+ "(msg:\"SMTP event handling\"; "
+ "app-layer-event: "
+ "smtp.invalid_pipelined_sequence; "
+ "sid:1;)");
+ if (s == NULL)
+ goto end;
+
+ SigGroupBuild(de_ctx);
+ DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER | STREAM_START,
+ request1, request1_len);
+ if (r != 0) {
+ printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ smtp_state = f.alstate;
+ if (smtp_state == NULL) {
+ printf("no smtp state: ");
+ goto end;
+ }
+
+ /* do detect */
+ SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
+
+ if (PacketAlertCheck(p, 1)) {
+ printf("sid 1 matched. It shouldn't match: ");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
+ reply1, reply1_len);
+ if (r != 0) {
+ printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ /* do detect */
+ SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
+
+ if (PacketAlertCheck(p, 1)) {
+ printf("sid 1 matched. It shouldn't match: ");
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request2, request2_len);
+ if (r != 0) {
+ printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ /* do detect */
+ SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
+
+ if (!PacketAlertCheck(p, 1)) {
+ printf("sid 1 didn't match. Should have matched: ");
+ goto end;
+ }
+
+ result = 1;
+
+end:
+ SigGroupCleanup(de_ctx);
+ SigCleanSignatures(de_ctx);
+
+ DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
+ DetectEngineCtxFree(de_ctx);
+
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ FLOW_DESTROY(&f);
+ UTHFreePackets(&p, 1);
+ return result;
+}
+
+/**
+ * \test Test DATA command w/MIME message.
+ */
+int SMTPParserTest14(void)
+{
+ int result = 0;
+ Flow f;
+ int r = 0;
+
+ /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
+ static uint8_t welcome_reply[] = {
+ 0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
+ 0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
+ 0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
+ 0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
+ 0x0d, 0x0a
+ };
+ static uint32_t welcome_reply_len = sizeof(welcome_reply);
+
+ /* EHLO boo.com<CR><LF> */
+ static uint8_t request1[] = {
+ 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
+ };
+ static uint32_t request1_len = sizeof(request1);
+ /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
+ * 250-SIZE 35882577<CR><LF>
+ * 250-8BITMIME<CR><LF>
+ * 250-STARTTLS<CR><LF>
+ * 250 ENHANCEDSTATUSCODES<CR><LF>
+ */
+ static uint8_t reply1[] = {
+ 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
+ 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
+ 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
+ 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
+ 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
+ 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
+ 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
+ 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
+ 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
+ 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
+ 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
+ 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
+ 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
+ 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
+ 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
+ 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
+ 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
+ };
+ static uint32_t reply1_len = sizeof(reply1);
+
+ /* MAIL FROM:asdff@asdf.com<CR><LF> */
+ static uint8_t request2[] = {
+ 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
+ 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
+ 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x0d, 0x0a
+ };
+ static uint32_t request2_len = sizeof(request2);
+ /* 250 2.1.0 Ok<CR><LF> */
+ static uint8_t reply2[] = {
+ 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
+ 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
+ };
+ static uint32_t reply2_len = sizeof(reply2);
+
+ /* RCPT TO:bimbs@gmail.com<CR><LF> */
+ static uint8_t request3[] = {
+ 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
+ 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
+ 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
+ 0x0a
+ };
+ static uint32_t request3_len = sizeof(request3);
+ /* 250 2.1.5 Ok<CR><LF> */
+ static uint8_t reply3[] = {
+ 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
+ 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
+ };
+ static uint32_t reply3_len = sizeof(reply3);
+
+ /* DATA<CR><LF> */
+ static uint8_t request4[] = {
+ 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
+ };
+ static uint32_t request4_len = sizeof(request4);
+ /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
+ static uint8_t reply4[] = {
+ 0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
+ 0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
+ 0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
+ 0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
+ 0x4c, 0x46, 0x3e, 0x0d, 0x0a
+ };
+ static uint32_t reply4_len = sizeof(reply4);
+
+ /* MIME_MSG */
+ static uint64_t filesize = 133;
+ static uint8_t request4_msg[] = {
+ 0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72,
+ 0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E,
+ 0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
+ 0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A,
+ 0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61,
+ 0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74,
+ 0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61,
+ 0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
+ 0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73,
+ 0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F,
+ 0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61,
+ 0x73, 0x65, 0x36, 0x34, 0x0D, 0x0A, 0x43, 0x6F,
+ 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x44, 0x69,
+ 0x73, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F,
+ 0x6E, 0x3A, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63,
+ 0x68, 0x6D, 0x65, 0x6E, 0x74, 0x3B, 0x20, 0x66,
+ 0x69, 0x6C, 0x65, 0x6E, 0x61, 0x6D, 0x65, 0x3D,
+ 0x22, 0x74, 0x65, 0x73, 0x74, 0x2E, 0x65, 0x78,
+ 0x65, 0x22, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x54,
+ 0x56, 0x6F, 0x41, 0x41, 0x46, 0x42, 0x46, 0x41,
+ 0x41, 0x42, 0x4D, 0x41, 0x51, 0x45, 0x41, 0x61,
+ 0x69, 0x70, 0x59, 0x77, 0x77, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
+ 0x41, 0x41, 0x44, 0x41, 0x51, 0x73, 0x42, 0x43,
+ 0x41, 0x41, 0x42, 0x41, 0x41, 0x43, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x48, 0x6B, 0x41, 0x41,
+ 0x41, 0x41, 0x4D, 0x41, 0x41, 0x41, 0x41, 0x65,
+ 0x51, 0x41, 0x41, 0x41, 0x41, 0x77, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x45, 0x41, 0x41, 0x42,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
+ 0x41, 0x42, 0x30, 0x41, 0x41, 0x41, 0x41, 0x49,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
+ 0x41, 0x45, 0x41, 0x41, 0x49, 0x67, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x67, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x42, 0x63, 0x58, 0x44, 0x59, 0x32, 0x4C,
+ 0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C,
+ 0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F,
+ 0x41, 0x3D, 0x3D, 0x0D,0x0A };
+ static uint32_t request4_msg_len = sizeof(request4_msg);
+
+ /* DATA COMPLETED */
+ static uint8_t request4_end[] = {
+ 0x0d, 0x0a, 0x2e, 0x0d, 0x0a
+ };
+ static uint32_t request4_end_len = sizeof(request4_end);
+ /* 250 2.0.0 Ok: queued as 6A1AF20BF2<CR><LF> */
+ static uint8_t reply4_end[] = {
+ 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
+ 0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
+ 0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
+ 0x36, 0x41, 0x31, 0x41, 0x46, 0x32, 0x30, 0x42,
+ 0x46, 0x32, 0x0d, 0x0a
+ };
+ static uint32_t reply4_end_len = sizeof(reply4_end);
+
+ /* QUIT<CR><LF> */
+ static uint8_t request5[] = {
+ 0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
+ };
+ static uint32_t request5_len = sizeof(request5);
+ /* 221 2.0.0 Bye<CR><LF> */
+ static uint8_t reply5[] = {
+ 0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
+ 0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
+ };
+ static uint32_t reply5_len = sizeof(reply5);
+
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&f, 0, sizeof(f));
+ memset(&ssn, 0, sizeof(ssn));
+
+ FLOW_INITIALIZE(&f);
+ f.protoctx = (void *)&ssn;
+ f.proto = IPPROTO_TCP;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f.m);
+ /* Welcome reply */
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
+ welcome_reply, welcome_reply_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ SMTPState *smtp_state = f.alstate;
+ if (smtp_state == NULL) {
+ printf("no smtp state: ");
+ goto end;
+ }
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
+ printf("smtp parser in inconsistent state l.%d\n", __LINE__);
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request1, request1_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 1 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
+ printf("smtp parser in inconsistent state l.%d\n", __LINE__);
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ /* EHLO Reply */
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
+ reply1, reply1_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
+ printf("smtp parser in inconsistent state l.%d\n", __LINE__);
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ /* MAIL FROM Request */
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request2, request2_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 1 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
+ printf("smtp parser in inconsistent state l.%d\n", __LINE__);
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ /* MAIL FROM Reply */
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
+ reply2, reply2_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
+ printf("smtp parser in inconsistent state l.%d\n", __LINE__);
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ /* RCPT TO Request */
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request3, request3_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 1 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
+ printf("smtp parser in inconsistent state l.%d\n", __LINE__);
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ /* RCPT TO Reply */
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
+ reply3, reply3_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
+ printf("smtp parser in inconsistent state l.%d\n", __LINE__);
+ goto end;
+ }
+
+ /* Enable mime decoding */
+ smtp_config.decode_mime = 1;
+ smtp_config.mime_config.decode_base64 = 1;
+ smtp_config.mime_config.decode_quoted_printable = 1;
+ MimeDecSetConfig(&smtp_config.mime_config);
+
+ SCMutexLock(&f.m);
+ /* DATA request */
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request4, request4_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 1 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
+ printf("smtp parser in inconsistent state l.%d\n", __LINE__);
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ /* Data reply */
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
+ reply4, reply4_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
+ SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
+ printf("smtp parser in inconsistent state l.%d\n", __LINE__);
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ /* DATA message */
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request4_msg, request4_msg_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->curr_tx->mime_state == NULL || smtp_state->curr_tx->msg_head == NULL || /* MIME data structures */
+ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
+ SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
+ printf("smtp parser in inconsistent state l.%d\n", __LINE__);
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ /* DATA . request */
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request4_end, request4_end_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 1 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
+ smtp_state->curr_tx->mime_state == NULL || smtp_state->curr_tx->msg_head == NULL || /* MIME data structures */
+ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
+ printf("smtp parser in inconsistent state l.%d\n", __LINE__);
+ goto end;
+ }
+
+ SMTPState *state = (SMTPState *) f.alstate;
+ FileContainer *files = state->files_ts;
+ if (files != NULL && files->head != NULL) {
+ File *file = files->head;
+
+ if(strncmp((const char *)file->name, "test.exe", 8) != 0){
+ printf("smtp-mime file name is incorrect");
+ goto end;
+ }
+ if(file->size != filesize){
+ printf("smtp-mime file size %"PRIu64" is incorrect", file->size);
+ goto end;
+ }
+ static uint8_t org_binary[] = {
+ 0x4D, 0x5A, 0x00, 0x00, 0x50, 0x45, 0x00, 0x00,
+ 0x4C, 0x01, 0x01, 0x00, 0x6A, 0x2A, 0x58, 0xC3,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x03, 0x01, 0x0B, 0x01, 0x08, 0x00,
+ 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x79, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
+ 0x79, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x40, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00,
+ 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5C, 0x5C, 0x36, 0x36,
+ 0x2E, 0x39, 0x33, 0x2E, 0x36, 0x38, 0x2E, 0x36,
+ 0x5C, 0x7A, 0x00, 0x00, 0x38,};
+ uint64_t z;
+ for (z=0; z < filesize; z++){
+ if(org_binary[z] != file->chunks_head->data[z]){
+ printf("smtp-mime file data incorrect\n");
+ goto end;
+ }
+ }
+ }
+
+ SCMutexLock(&f.m);
+ /* DATA . reply */
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
+ reply4_end, reply4_end_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
+ printf("smtp parser in inconsistent state l.%d\n", __LINE__);
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ /* QUIT Request */
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOSERVER,
+ request5, request5_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 1 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
+ smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
+ printf("smtp parser in inconsistent state l.%d\n", __LINE__);
+ goto end;
+ }
+
+ SCMutexLock(&f.m);
+ /* QUIT Reply */
+ r = AppLayerParserParse(alp_tctx, &f, ALPROTO_SMTP, STREAM_TOCLIENT,
+ reply5, reply5_len);
+ if (r != 0) {
+ printf("smtp check returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f.m);
+ goto end;
+ }
+ SCMutexUnlock(&f.m);
+ if (smtp_state->input_len != 0 ||
+ smtp_state->cmds_cnt != 0 ||
+ smtp_state->cmds_idx != 0 ||
+ smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
+ printf("smtp parser in inconsistent state l.%d\n", __LINE__);
+ goto end;
+ }
+
+ result = 1;
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ FLOW_DESTROY(&f);
+ return result;
+}
+
+int SMTPProcessDataChunkTest01(void){
+ Flow f;
+ FLOW_INITIALIZE(&f);
+ f.flags = FLOW_FILE_NO_STORE_TS;
+ MimeDecParseState *state = MimeDecInitParser(&f, NULL);
+ int ret;
+ ret = SMTPProcessDataChunk(NULL, 0, state);
+
+ return ret;
+}
+
+
+int SMTPProcessDataChunkTest02(void){
+ char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72,
+ 0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E,
+ 0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
+ 0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A,
+ 0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61,
+ 0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74,
+ 0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61,
+ 0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
+ 0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73,
+ 0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F,
+ 0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61,
+ 0x73, 0x65, 0x36, 0x34, 0x0D, 0x0A, 0x43, 0x6F,
+ 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x44, 0x69,
+ 0x73, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F,
+ 0x6E, 0x3A, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63,
+ 0x68, 0x6D, 0x65, 0x6E, 0x74, 0x3B, 0x20, 0x66,
+ 0x69, 0x6C, 0x65, 0x6E, 0x61, 0x6D, 0x65, 0x3D,
+ 0x22, 0x74, 0x65, 0x73, 0x74, 0x2E, 0x65, 0x78,
+ 0x65, 0x22, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x54,
+ 0x56, 0x6F, 0x41, 0x41, 0x46, 0x42, 0x46, 0x41,
+ 0x41, 0x42, 0x4D, 0x41, 0x51, 0x45, 0x41, 0x61,
+ 0x69, 0x70, 0x59, 0x77, 0x77, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
+ 0x41, 0x41, 0x44, 0x41, 0x51, 0x73, 0x42, 0x43,
+ 0x41, 0x41, 0x42, 0x41, 0x41, 0x43, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x48, 0x6B, 0x41, 0x41,
+ 0x41, 0x41, 0x4D, 0x41, 0x41, 0x41, 0x41, 0x65,
+ 0x51, 0x41, 0x41, 0x41, 0x41, 0x77, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x45, 0x41, 0x41, 0x42,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
+ 0x41, 0x42, 0x30, 0x41, 0x41, 0x41, 0x41, 0x49,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
+ 0x41, 0x45, 0x41, 0x41, 0x49, 0x67, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x67, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x42, 0x63, 0x58, 0x44, 0x59, 0x32, 0x4C,
+ 0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C,
+ 0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F,
+ 0x41, 0x3D, 0x3D, 0x0D, 0x0A,};
+
+ Flow f;
+ FLOW_INITIALIZE(&f);
+ f.alstate = SMTPStateAlloc();
+ MimeDecParseState *state = MimeDecInitParser(&f, NULL);
+ ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT;
+ state->body_begin = 1;
+ int ret;
+ ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state);
+
+
+ return ret;
+}
+
+
+
+int SMTPProcessDataChunkTest03(void){
+ char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, };
+ char mimemsg2[] = {0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, };
+ char mimemsg3[] = {0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, };
+ char mimemsg4[] = {0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A, };
+ char mimemsg5[] = {0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, };
+ char mimemsg6[] = {0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74, };
+ char mimemsg7[] = {0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61, };
+ char mimemsg8[] = {0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, };
+ char mimemsg9[] = {0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73, };
+ char mimemsg10[] = {0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F, };
+ char mimemsg11[] = {0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61, };
+ char mimemsg12[] = {0x73, 0x65, 0x36, 0x34, 0x0D, 0x0A, 0x43, 0x6F, };
+
+ Flow f;
+ FLOW_INITIALIZE(&f);
+ f.alstate = SMTPStateAlloc();
+ MimeDecParseState *state = MimeDecInitParser(&f, NULL);
+ ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT;
+ int ret;
+
+ state->body_begin = 1;
+ ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state);
+ if(ret) goto end;
+ state->body_begin = 0;
+ ret = SMTPProcessDataChunk((uint8_t *)mimemsg2, sizeof(mimemsg2), state);
+ if(ret) goto end;
+ ret = SMTPProcessDataChunk((uint8_t *)mimemsg3, sizeof(mimemsg3), state);
+ if(ret) goto end;
+ ret = SMTPProcessDataChunk((uint8_t *)mimemsg4, sizeof(mimemsg4), state);
+ if(ret) goto end;
+ ret = SMTPProcessDataChunk((uint8_t *)mimemsg5, sizeof(mimemsg5), state);
+ if(ret) goto end;
+ ret = SMTPProcessDataChunk((uint8_t *)mimemsg6, sizeof(mimemsg6), state);
+ if(ret) goto end;
+ ret = SMTPProcessDataChunk((uint8_t *)mimemsg7, sizeof(mimemsg7), state);
+ if(ret) goto end;
+ ret = SMTPProcessDataChunk((uint8_t *)mimemsg8, sizeof(mimemsg8), state);
+ if(ret) goto end;
+ ret = SMTPProcessDataChunk((uint8_t *)mimemsg9, sizeof(mimemsg9), state);
+ if(ret) goto end;
+ ret = SMTPProcessDataChunk((uint8_t *)mimemsg10, sizeof(mimemsg10), state);
+ if(ret) goto end;
+ ret = SMTPProcessDataChunk((uint8_t *)mimemsg11, sizeof(mimemsg11), state);
+ if(ret) goto end;
+ state->body_end = 1;
+ ret = SMTPProcessDataChunk((uint8_t *)mimemsg12, sizeof(mimemsg12), state);
+ if(ret) goto end;
+
+ end:
+ return ret;
+}
+
+
+int SMTPProcessDataChunkTest04(void){
+ char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, };
+ char mimemsg2[] = {0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, };
+ char mimemsg3[] = {0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, };
+ char mimemsg4[] = {0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A, };
+ char mimemsg5[] = {0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, };
+ char mimemsg6[] = {0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74, };
+ char mimemsg7[] = {0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61, };
+ char mimemsg8[] = {0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, };
+ char mimemsg9[] = {0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73, };
+ char mimemsg10[] = {0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F, };
+ char mimemsg11[] = {0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61, };
+
+ Flow f;
+ FLOW_INITIALIZE(&f);
+ f.alstate = SMTPStateAlloc();
+ MimeDecParseState *state = MimeDecInitParser(&f, NULL);
+ ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT;
+ int ret = MIME_DEC_OK;
+
+ state->body_begin = 1;
+ if(SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state) != 0) goto end;
+ if(SMTPProcessDataChunk((uint8_t *)mimemsg2, sizeof(mimemsg2), state) != 0) goto end;
+ if(SMTPProcessDataChunk((uint8_t *)mimemsg3, sizeof(mimemsg3), state) != 0) goto end;
+ if(SMTPProcessDataChunk((uint8_t *)mimemsg4, sizeof(mimemsg4), state) != 0) goto end;
+ if(SMTPProcessDataChunk((uint8_t *)mimemsg5, sizeof(mimemsg5), state) != 0) goto end;
+ if(SMTPProcessDataChunk((uint8_t *)mimemsg6, sizeof(mimemsg6), state) != 0) goto end;
+ if(SMTPProcessDataChunk((uint8_t *)mimemsg7, sizeof(mimemsg7), state) != 0) goto end;
+ state->body_begin = 0;
+ state->body_end = 1;
+ if(SMTPProcessDataChunk((uint8_t *)mimemsg8, sizeof(mimemsg8), state) != 0) goto end;
+ state->body_end = 0;
+ if(SMTPProcessDataChunk((uint8_t *)mimemsg9, sizeof(mimemsg9), state) != 0) goto end;
+ if(SMTPProcessDataChunk((uint8_t *)mimemsg10, sizeof(mimemsg10), state) != 0) goto end;
+ if(SMTPProcessDataChunk((uint8_t *)mimemsg11, sizeof(mimemsg11), state) != 0) goto end;
+
+ end:
+ return ret;
+}
+
+int SMTPProcessDataChunkTest05(void){
+ char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72,
+ 0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E,
+ 0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
+ 0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A,
+ 0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C,
+ 0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F,
+ 0x41, 0x3D, 0x3D, 0x0D, 0x0A,};
+
+ Flow f;
+ FLOW_INITIALIZE(&f);
+ f.alstate = SMTPStateAlloc();
+ MimeDecParseState *state = MimeDecInitParser(&f, NULL);
+ ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT;
+ state->body_begin = 1;
+ int ret;
+ uint64_t file_size = 0;
+ ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state);
+ state->body_begin = 0;
+ if(ret){goto end;}
+ SMTPState *smtp_state = (SMTPState *)((Flow *)state->data)->alstate;
+ FileContainer *files = smtp_state->files_ts;
+ File *file = files->head;
+ file_size = file->size;
+
+ FileDisableStoring(&f, STREAM_TOSERVER);
+ FileDisableMagic(&f, STREAM_TOSERVER);
+ FileDisableMd5(&f, STREAM_TOSERVER);
+ ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state);
+ if(ret){goto end;}
+ printf("%u\t%u\n", (uint32_t) file->size, (uint32_t) file_size);
+ if(file->size == file_size){
+ return 0;
+ }else{
+ return 1;
+ }
+
+ end:
+ return ret;
+}
+
+#endif /* UNITTESTS */
+
+void SMTPParserRegisterTests(void)
+{
+#ifdef UNITTESTS
+ UtRegisterTest("SMTPParserTest01", SMTPParserTest01, 1);
+ UtRegisterTest("SMTPParserTest02", SMTPParserTest02, 1);
+ UtRegisterTest("SMTPParserTest03", SMTPParserTest03, 1);
+ UtRegisterTest("SMTPParserTest04", SMTPParserTest04, 1);
+ UtRegisterTest("SMTPParserTest05", SMTPParserTest05, 1);
+ UtRegisterTest("SMTPParserTest06", SMTPParserTest06, 1);
+ UtRegisterTest("SMTPParserTest07", SMTPParserTest07, 1);
+ UtRegisterTest("SMTPParserTest08", SMTPParserTest08, 1);
+ UtRegisterTest("SMTPParserTest09", SMTPParserTest09, 1);
+ UtRegisterTest("SMTPParserTest10", SMTPParserTest10, 1);
+ UtRegisterTest("SMTPParserTest11", SMTPParserTest11, 1);
+ UtRegisterTest("SMTPParserTest12", SMTPParserTest12, 1);
+ UtRegisterTest("SMTPParserTest13", SMTPParserTest13, 1);
+ UtRegisterTest("SMTPParserTest14", SMTPParserTest14, 1);
+ UtRegisterTest("SMTPProcessDataChunkTest01", SMTPProcessDataChunkTest01, 0);
+ UtRegisterTest("SMTPProcessDataChunkTest02", SMTPProcessDataChunkTest02, 0);
+ UtRegisterTest("SMTPProcessDataChunkTest03", SMTPProcessDataChunkTest03, 0);
+ UtRegisterTest("SMTPProcessDataChunkTest04", SMTPProcessDataChunkTest04, 0);
+ UtRegisterTest("SMTPProcessDataChunkTest05", SMTPProcessDataChunkTest05, 0);
+#endif /* UNITTESTS */
+
+ return;
+}