suricata
app-layer-smtp.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2021 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \file
20  *
21  * \author Anoop Saldanha <anoopsaldanha@gmail.com>
22  */
23 
24 #include "suricata.h"
25 #include "suricata-common.h"
26 #include "debug.h"
27 #include "decode.h"
28 #include "threads.h"
29 
30 #include "stream-tcp-private.h"
31 #include "stream-tcp-reassemble.h"
32 #include "stream-tcp.h"
33 #include "stream.h"
34 
35 #include "app-layer.h"
36 #include "app-layer-detect-proto.h"
37 #include "app-layer-protos.h"
38 #include "app-layer-parser.h"
39 #include "app-layer-smtp.h"
40 
41 #include "util-mpm.h"
42 #include "util-debug.h"
43 #include "util-byte.h"
44 #include "util-unittest.h"
45 #include "util-unittest-helper.h"
46 #include "util-memcmp.h"
47 #include "flow-util.h"
48 
49 #include "detect-engine.h"
50 #include "detect-engine-state.h"
51 #include "detect-parse.h"
52 
53 #include "decode-events.h"
54 #include "conf.h"
55 
56 #include "util-mem.h"
57 #include "util-misc.h"
58 #include "util-validate.h"
59 
60 /* content-limit default value */
61 #define FILEDATA_CONTENT_LIMIT 100000
62 /* content-inspect-min-size default value */
63 #define FILEDATA_CONTENT_INSPECT_MIN_SIZE 32768
64 /* content-inspect-window default value */
65 #define FILEDATA_CONTENT_INSPECT_WINDOW 4096
66 
67 /* raw extraction default value */
68 #define SMTP_RAW_EXTRACTION_DEFAULT_VALUE false
69 #define SMTP_MAX_REQUEST_AND_REPLY_LINE_LENGTH 510
70 
71 #define SMTP_COMMAND_BUFFER_STEPS 5
72 
73 /* we are in process of parsing a fresh command. Just a placeholder. If we
74  * are not in STATE_COMMAND_DATA_MODE, we have to be in this mode */
75 #define SMTP_PARSER_STATE_COMMAND_MODE 0x00
76 /* we are in mode of parsing a command's data. Used when we are parsing tls
77  * or accepting the rfc 2822 mail after DATA command */
78 #define SMTP_PARSER_STATE_COMMAND_DATA_MODE 0x01
79 /* Used when we are still in the process of parsing a server command. Used
80  * with multi-line replies and the stream is fragmented before all the lines
81  * for a response is seen */
82 #define SMTP_PARSER_STATE_PARSING_SERVER_RESPONSE 0x02
83 /* Used to indicate that the parser has seen the first reply */
84 #define SMTP_PARSER_STATE_FIRST_REPLY_SEEN 0x04
85 /* Used to indicate that the parser is parsing a multiline reply */
86 #define SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY 0x08
87 /* Used to indicate that the server supports pipelining */
88 #define SMTP_PARSER_STATE_PIPELINING_SERVER 0x10
89 
90 /* Various SMTP commands
91  * We currently have var-ified just STARTTLS and DATA, since we need to them
92  * for state transitions. The rest are just indicate as OTHER_CMD. Other
93  * commands would be introduced as and when needed */
94 #define SMTP_COMMAND_STARTTLS 1
95 #define SMTP_COMMAND_DATA 2
96 #define SMTP_COMMAND_BDAT 3
97 /* not an actual command per se, but the mode where we accept the mail after
98  * DATA has it's own reply code for completion, from the server. We give this
99  * stage a pseudo command of it's own, so that we can add this to the command
100  * buffer to match with the reply */
101 #define SMTP_COMMAND_DATA_MODE 4
102 /* All other commands are represented by this var */
103 #define SMTP_COMMAND_OTHER_CMD 5
104 #define SMTP_COMMAND_RSET 6
105 
106 /* Different EHLO extensions. Not used now. */
107 #define SMTP_EHLO_EXTENSION_PIPELINING
108 #define SMTP_EHLO_EXTENSION_SIZE
109 #define SMTP_EHLO_EXTENSION_DSN
110 #define SMTP_EHLO_EXTENSION_STARTTLS
111 #define SMTP_EHLO_EXTENSION_8BITMIME
112 /* Limit till the data would be buffered in current line */
113 #define SMTP_LINE_BUFFER_LIMIT 4096
114 
116  { "INVALID_REPLY", SMTP_DECODER_EVENT_INVALID_REPLY },
117  { "UNABLE_TO_MATCH_REPLY_WITH_REQUEST", SMTP_DECODER_EVENT_UNABLE_TO_MATCH_REPLY_WITH_REQUEST },
118  { "MAX_COMMAND_LINE_LEN_EXCEEDED", SMTP_DECODER_EVENT_MAX_COMMAND_LINE_LEN_EXCEEDED },
119  { "MAX_REPLY_LINE_LEN_EXCEEDED", SMTP_DECODER_EVENT_MAX_REPLY_LINE_LEN_EXCEEDED },
120  { "INVALID_PIPELINED_SEQUENCE", SMTP_DECODER_EVENT_INVALID_PIPELINED_SEQUENCE },
121  { "BDAT_CHUNK_LEN_EXCEEDED", SMTP_DECODER_EVENT_BDAT_CHUNK_LEN_EXCEEDED },
122  { "NO_SERVER_WELCOME_MESSAGE", SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE },
123  { "TLS_REJECTED", SMTP_DECODER_EVENT_TLS_REJECTED },
124  { "DATA_COMMAND_REJECTED", SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED },
125 
126  /* MIME Events */
127  { "MIME_PARSE_FAILED", SMTP_DECODER_EVENT_MIME_PARSE_FAILED },
128  { "MIME_MALFORMED_MSG", SMTP_DECODER_EVENT_MIME_MALFORMED_MSG },
129  { "MIME_INVALID_BASE64", SMTP_DECODER_EVENT_MIME_INVALID_BASE64 },
130  { "MIME_INVALID_QP", SMTP_DECODER_EVENT_MIME_INVALID_QP },
131  { "MIME_LONG_LINE", SMTP_DECODER_EVENT_MIME_LONG_LINE },
132  { "MIME_LONG_ENC_LINE", SMTP_DECODER_EVENT_MIME_LONG_ENC_LINE },
133  { "MIME_LONG_HEADER_NAME", SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME },
134  { "MIME_LONG_HEADER_VALUE", SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE },
135  { "MIME_LONG_BOUNDARY", SMTP_DECODER_EVENT_MIME_BOUNDARY_TOO_LONG },
136  { "MIME_LONG_FILENAME", SMTP_DECODER_EVENT_MIME_LONG_FILENAME },
137 
138  /* Invalid behavior or content */
139  { "DUPLICATE_FIELDS", SMTP_DECODER_EVENT_DUPLICATE_FIELDS },
140  { "UNPARSABLE_CONTENT", SMTP_DECODER_EVENT_UNPARSABLE_CONTENT },
141  { "TRUNCATED_LINE", SMTP_DECODER_EVENT_TRUNCATED_LINE },
142  { NULL, -1 },
143 };
144 
145 typedef struct SMTPThreadCtx_ {
149 
150 #define SMTP_MPM mpm_default_matcher
151 
152 static MpmCtx *smtp_mpm_ctx = NULL;
153 
154 /* smtp reply codes. If an entry is made here, please make a simultaneous
155  * entry in smtp_reply_map */
156 enum SMTPCode {
165 
168 
174 
186 };
187 
189  { "211", SMTP_REPLY_211 },
190  { "214", SMTP_REPLY_214 },
191  { "220", SMTP_REPLY_220 },
192  { "221", SMTP_REPLY_221 },
193  { "235", SMTP_REPLY_235 },
194  { "250", SMTP_REPLY_250 },
195  { "251", SMTP_REPLY_251 },
196  { "252", SMTP_REPLY_252 },
197 
198  { "334", SMTP_REPLY_334 },
199  { "354", SMTP_REPLY_354 },
200 
201  { "421", SMTP_REPLY_421 },
202  { "450", SMTP_REPLY_450 },
203  { "451", SMTP_REPLY_451 },
204  { "452", SMTP_REPLY_452 },
205  { "455", SMTP_REPLY_455 },
206 
207  { "500", SMTP_REPLY_500 },
208  { "501", SMTP_REPLY_501 },
209  { "502", SMTP_REPLY_502 },
210  { "503", SMTP_REPLY_503 },
211  { "504", SMTP_REPLY_504 },
212  { "550", SMTP_REPLY_550 },
213  { "551", SMTP_REPLY_551 },
214  { "552", SMTP_REPLY_552 },
215  { "553", SMTP_REPLY_553 },
216  { "554", SMTP_REPLY_554 },
217  { "555", SMTP_REPLY_555 },
218  { NULL, -1 },
219 };
220 
221 /* Create SMTP config structure */
222 SMTPConfig smtp_config = { false, { false, false, false, NULL, false, false, 0 }, 0, 0, 0, false,
224 
225 static SMTPString *SMTPStringAlloc(void);
226 static int SMTPPreProcessCommands(SMTPState *state, Flow *f, AppLayerParserState *pstate);
227 
228 /**
229  * \brief Configure SMTP Mime Decoder by parsing out mime section of YAML
230  * config file
231  *
232  * \return none
233  */
234 static void SMTPConfigure(void) {
235 
236  SCEnter();
237  intmax_t imval;
238  uint32_t content_limit = 0;
239  uint32_t content_inspect_min_size = 0;
240  uint32_t content_inspect_window = 0;
241 
242  ConfNode *config = ConfGetNode("app-layer.protocols.smtp.mime");
243  if (config != NULL) {
244  ConfNode *extract_urls_schemes = NULL;
245 
246  int val;
247  int ret = ConfGetChildValueBool(config, "decode-mime", &val);
248  if (ret) {
249  smtp_config.decode_mime = val;
250  }
251 
252  ret = ConfGetChildValueBool(config, "decode-base64", &val);
253  if (ret) {
255  }
256 
257  ret = ConfGetChildValueBool(config, "decode-quoted-printable", &val);
258  if (ret) {
260  }
261 
262  ret = ConfGetChildValueInt(config, "header-value-depth", &imval);
263  if (ret) {
264  smtp_config.mime_config.header_value_depth = (uint32_t) imval;
265  }
266 
267  ret = ConfGetChildValueBool(config, "extract-urls", &val);
268  if (ret) {
270  }
271 
272  /* Parse extract-urls-schemes from mime config, add '://' suffix to found schemes,
273  * and provide a default value of 'http' for the schemes to be extracted
274  * if no schemes are found in the config */
275  extract_urls_schemes = ConfNodeLookupChild(config, "extract-urls-schemes");
276  if (extract_urls_schemes) {
277  ConfNode *scheme = NULL;
278 
279  TAILQ_FOREACH (scheme, &extract_urls_schemes->head, next) {
280  /* new_val_len: scheme value from config e.g. 'http' + '://' + null terminator */
281  size_t new_val_len = strlen(scheme->val) + 3 + 1;
282  if (new_val_len > UINT16_MAX) {
283  FatalError(SC_ERR_FATAL, "Too long value for extract-urls-schemes");
284  }
285  char *new_val = SCMalloc(new_val_len);
286  if (unlikely(new_val == NULL)) {
287  FatalError(SC_ERR_FATAL, "SCMalloc failure.");
288  }
289 
290  int r = snprintf(new_val, new_val_len, "%s://", scheme->val);
291  if (r < 0 || r >= (int)new_val_len) {
292  FatalError(SC_ERR_FATAL, "snprintf failure.");
293  }
294 
295  /* replace existing scheme value stored on the linked list with new value including
296  * '://' suffix */
297  SCFree(scheme->val);
298  scheme->val = new_val;
299  }
300 
301  smtp_config.mime_config.extract_urls_schemes = extract_urls_schemes;
302  } else {
303  /* Add default extract url scheme 'http' since
304  * extract-urls-schemes wasn't found in the config */
305  ConfNode *seq_node = ConfNodeNew();
306  if (unlikely(seq_node == NULL)) {
307  FatalError(SC_ERR_FATAL, "ConfNodeNew failure.");
308  }
309  ConfNode *scheme = ConfNodeNew();
310  if (unlikely(scheme == NULL)) {
311  FatalError(SC_ERR_FATAL, "ConfNodeNew failure.");
312  }
313 
314  seq_node->name = SCStrdup("extract-urls-schemes");
315  if (unlikely(seq_node->name == NULL)) {
316  FatalError(SC_ERR_FATAL, "SCStrdup failure.");
317  }
318  scheme->val = SCStrdup("http");
319  if (unlikely(scheme->val == NULL)) {
320  FatalError(SC_ERR_FATAL, "SCStrdup failure.");
321  }
322 
323  seq_node->is_seq = 1;
324  TAILQ_INSERT_TAIL(&seq_node->head, scheme, next);
325  TAILQ_INSERT_TAIL(&config->head, seq_node, next);
326 
328  }
329 
330  ret = ConfGetChildValueBool(config, "log-url-scheme", &val);
331  if (ret) {
333  }
334 
335  ret = ConfGetChildValueBool(config, "body-md5", &val);
336  if (ret) {
338  }
339  }
340 
341  /* Pass mime config data to MimeDec API */
343 
347 
348  ConfNode *t = ConfGetNode("app-layer.protocols.smtp.inspected-tracker");
349  ConfNode *p = NULL;
350 
351  if (t != NULL) {
352  TAILQ_FOREACH(p, &t->head, next) {
353  if (strcasecmp("content-limit", p->name) == 0) {
354  if (ParseSizeStringU32(p->val, &content_limit) < 0) {
356  "parsing content-limit %s failed", p->val);
357  content_limit = FILEDATA_CONTENT_LIMIT;
358  }
359  smtp_config.content_limit = content_limit;
360  }
361 
362  if (strcasecmp("content-inspect-min-size", p->name) == 0) {
363  if (ParseSizeStringU32(p->val, &content_inspect_min_size) < 0) {
365  "parsing content-inspect-min-size %s failed", p->val);
366  content_inspect_min_size = FILEDATA_CONTENT_INSPECT_MIN_SIZE;
367  }
368  smtp_config.content_inspect_min_size = content_inspect_min_size;
369  }
370 
371  if (strcasecmp("content-inspect-window", p->name) == 0) {
372  if (ParseSizeStringU32(p->val, &content_inspect_window) < 0) {
374  "parsing content-inspect-window %s failed", p->val);
375  content_inspect_window = FILEDATA_CONTENT_INSPECT_WINDOW;
376  }
377  smtp_config.content_inspect_window = content_inspect_window;
378  }
379  }
380  }
381 
382  smtp_config.sbcfg.buf_size = content_limit ? content_limit : 256;
383 
384  if (ConfGetBool("app-layer.protocols.smtp.raw-extraction",
385  (int *)&smtp_config.raw_extraction) != 1) {
387  }
390  "\"decode-mime\" and \"raw-extraction\" "
391  "options can't be enabled at the same time, "
392  "disabling raw extraction");
394  }
395 
396  SCReturn;
397 }
398 
399 static void SMTPSetEvent(SMTPState *s, uint8_t e)
400 {
401  SCLogDebug("setting event %u", e);
402 
403  if (s->curr_tx != NULL) {
405  // s->events++;
406  return;
407  }
408  SCLogDebug("couldn't set event %u", e);
409 }
410 
411 static SMTPTransaction *SMTPTransactionCreate(void)
412 {
413  SMTPTransaction *tx = SCCalloc(1, sizeof(*tx));
414  if (tx == NULL) {
415  return NULL;
416  }
417 
418  TAILQ_INIT(&tx->rcpt_to_list);
419  tx->mime_state = NULL;
420  return tx;
421 }
422 
423 static void FlagDetectStateNewFile(SMTPTransaction *tx)
424 {
425  if (tx && tx->tx_data.de_state) {
426  SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_NEW set");
427  tx->tx_data.de_state->dir_state[0].flags |= DETECT_ENGINE_STATE_FLAG_FILE_NEW;
428  } else if (tx == NULL) {
429  SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_NEW NOT set, no TX");
430  } else if (tx->tx_data.de_state == NULL) {
431  SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_NEW NOT set, no TX DESTATE");
432  }
433 }
434 
435 static void SMTPNewFile(SMTPTransaction *tx, File *file)
436 {
437  DEBUG_VALIDATE_BUG_ON(tx == NULL);
438  DEBUG_VALIDATE_BUG_ON(file == NULL);
439 #ifdef UNITTESTS
440  if (RunmodeIsUnittests()) {
441  if (tx == NULL || file == NULL) {
442  return;
443  }
444  }
445 #endif
446  FlagDetectStateNewFile(tx);
447  FileSetTx(file, tx->tx_id);
448  tx->tx_data.files_opened++;
449 
450  /* set inspect sizes used in file pruning logic.
451  * TODO consider moving this to the file.data code that
452  * would actually have use for this. */
455 }
456 
457 int SMTPProcessDataChunk(const uint8_t *chunk, uint32_t len,
458  MimeDecParseState *state)
459 {
460  SCEnter();
461  int ret = MIME_DEC_OK;
462  Flow *flow = (Flow *) state->data;
463  SMTPState *smtp_state = (SMTPState *) flow->alstate;
464  MimeDecEntity *entity = (MimeDecEntity *) state->stack->top->data;
465  FileContainer *files = NULL;
466 
467  uint16_t flags = FileFlowToFlags(flow, STREAM_TOSERVER);
468  /* we depend on detection engine for file pruning */
470 
471  /* Find file */
472  if (entity->ctnt_flags & CTNT_IS_ATTACHMENT) {
473 
474  /* Make sure file container allocated */
475  if (smtp_state->files_ts == NULL) {
476  smtp_state->files_ts = FileContainerAlloc();
477  if (smtp_state->files_ts == NULL) {
478  ret = MIME_DEC_ERR_MEM;
479  SCLogError(SC_ERR_MEM_ALLOC, "Could not create file container");
480  SCReturnInt(ret);
481  }
482  }
483  files = smtp_state->files_ts;
484 
485  /* Open file if necessary */
486  if (state->body_begin) {
487 
488  if (SCLogDebugEnabled()) {
489  SCLogDebug("Opening file...%u bytes", len);
490  printf("File - ");
491  for (uint32_t i = 0; i < entity->filename_len; i++) {
492  printf("%c", entity->filename[i]);
493  }
494  printf("\n");
495  }
496 
497  /* Set storage flag if applicable since only the first file in the
498  * flow seems to be processed by the 'filestore' detector */
499  if (files->head != NULL && (files->head->flags & FILE_STORE)) {
500  flags |= FILE_STORE;
501  }
502 
503  uint32_t depth = smtp_config.content_inspect_min_size +
504  (smtp_state->toserver_data_count - smtp_state->toserver_last_data_stamp);
505  SCLogDebug("StreamTcpReassemblySetMinInspectDepth STREAM_TOSERVER %"PRIu32, depth);
506  StreamTcpReassemblySetMinInspectDepth(flow->protoctx, STREAM_TOSERVER, depth);
507 
508  uint16_t flen = (uint16_t)entity->filename_len;
509  if (entity->filename_len > SC_FILENAME_MAX) {
510  flen = SC_FILENAME_MAX;
511  SMTPSetEvent(smtp_state, SMTP_DECODER_EVENT_MIME_LONG_FILENAME);
512  }
513  if (FileOpenFileWithId(files, &smtp_config.sbcfg, smtp_state->file_track_id++,
514  (uint8_t *)entity->filename, flen, (uint8_t *)chunk, len, flags) != 0) {
515  ret = MIME_DEC_ERR_DATA;
516  SCLogDebug("FileOpenFile() failed");
517  }
518  SMTPNewFile(smtp_state->curr_tx, files->tail);
519 
520  /* If close in the same chunk, then pass in empty bytes */
521  if (state->body_end) {
522 
523  SCLogDebug("Closing file...%u bytes", len);
524 
525  if (files->tail->state == FILE_STATE_OPENED) {
526  ret = FileCloseFile(files, (uint8_t *) NULL, 0, flags);
527  if (ret != 0) {
528  SCLogDebug("FileCloseFile() failed: %d", ret);
529  ret = MIME_DEC_ERR_DATA;
530  }
531  } else {
532  SCLogDebug("File already closed");
533  }
534  depth = smtp_state->toserver_data_count - smtp_state->toserver_last_data_stamp;
535 
536  AppLayerParserTriggerRawStreamReassembly(flow, STREAM_TOSERVER);
537  SCLogDebug("StreamTcpReassemblySetMinInspectDepth STREAM_TOSERVER %u",
538  depth);
539  StreamTcpReassemblySetMinInspectDepth(flow->protoctx, STREAM_TOSERVER,
540  depth);
541  }
542  } else if (state->body_end) {
543  /* Close file */
544  SCLogDebug("Closing file...%u bytes", len);
545 
546  if (files->tail && files->tail->state == FILE_STATE_OPENED) {
547  ret = FileCloseFile(files, (uint8_t *) chunk, len, flags);
548  if (ret != 0) {
549  SCLogDebug("FileCloseFile() failed: %d", ret);
550  ret = MIME_DEC_ERR_DATA;
551  }
552  } else {
553  SCLogDebug("File already closed");
554  }
555  uint32_t depth = smtp_state->toserver_data_count - smtp_state->toserver_last_data_stamp;
556  AppLayerParserTriggerRawStreamReassembly(flow, STREAM_TOSERVER);
557  SCLogDebug("StreamTcpReassemblySetMinInspectDepth STREAM_TOSERVER %u",
558  depth);
560  STREAM_TOSERVER, depth);
561  } else {
562  /* Append data chunk to file */
563  SCLogDebug("Appending file...%u bytes", len);
564 
565  /* 0 is ok, -2 is not stored, -1 is error */
566  ret = FileAppendData(files, (uint8_t *) chunk, len);
567  if (ret == -2) {
568  ret = 0;
569  SCLogDebug("FileAppendData() - file no longer being extracted");
570  } else if (ret < 0) {
571  SCLogDebug("FileAppendData() failed: %d", ret);
572  ret = MIME_DEC_ERR_DATA;
573  }
574 
575  if (files->tail && files->tail->content_inspected == 0 &&
576  files->tail->size >= smtp_config.content_inspect_min_size) {
577  uint32_t depth = smtp_config.content_inspect_min_size +
578  (smtp_state->toserver_data_count - smtp_state->toserver_last_data_stamp);
579  AppLayerParserTriggerRawStreamReassembly(flow, STREAM_TOSERVER);
580  SCLogDebug("StreamTcpReassemblySetMinInspectDepth STREAM_TOSERVER %u",
581  depth);
583  STREAM_TOSERVER, depth);
584 
585  /* after the start of the body inspection, disable the depth logic */
586  } else if (files->tail && files->tail->content_inspected > 0) {
588  STREAM_TOSERVER, 0);
589 
590  /* expand the limit as long as we get file data, as the file data is bigger on the
591  * wire due to base64 */
592  } else {
593  uint32_t depth = smtp_config.content_inspect_min_size +
594  (smtp_state->toserver_data_count - smtp_state->toserver_last_data_stamp);
595  SCLogDebug("StreamTcpReassemblySetMinInspectDepth STREAM_TOSERVER %"PRIu32,
596  depth);
598  STREAM_TOSERVER, depth);
599  }
600  }
601 
602  if (ret == 0) {
603  SCLogDebug("Successfully processed file data!");
604  }
605  } else {
606  SCLogDebug("Body not a Ctnt_attachment");
607  }
608  SCReturnInt(ret);
609 }
610 
611 /**
612  * \internal
613  * \brief Get the next line from input. It doesn't do any length validation.
614  *
615  * \param state The smtp state.
616  *
617  * \retval 0 On success.
618  * \retval -1 Either when we don't have any new lines to supply anymore or
619  * on failure.
620  */
621 static AppLayerResult SMTPGetLine(SMTPState *state)
622 {
623  SCEnter();
624 
625  /* we have run out of input */
626  if (state->input_len <= 0)
627  return APP_LAYER_ERROR;
628 
629  uint8_t *lf_idx = memchr(state->input + state->consumed, 0x0a, state->input_len);
630 
631  if (lf_idx == NULL) {
632  if (!state->discard_till_lf && state->input_len >= SMTP_LINE_BUFFER_LIMIT) {
633  state->current_line = state->input;
635  state->current_line_delimiter_len = 0;
637  }
639  } else {
640  uint32_t o_consumed = state->consumed;
641  state->consumed = lf_idx - state->input + 1;
642  state->current_line_len = state->consumed - o_consumed;
643  state->input_len -= state->current_line_len;
644  DEBUG_VALIDATE_BUG_ON((state->consumed + state->input_len) != state->orig_input_len);
645  if (state->discard_till_lf) {
646  // Whatever came in with first LF should also get discarded
647  state->discard_till_lf = false;
648  state->current_line_len = 0;
650  }
651  state->current_line = state->input + o_consumed;
652  if (state->consumed >= 2 && state->input[state->consumed - 2] == 0x0D) {
653  state->current_line_delimiter_len = 2;
654  state->current_line_len -= 2;
655  } else {
656  state->current_line_delimiter_len = 1;
657  state->current_line_len -= 1;
658  }
660  }
661 }
662 
663 static int SMTPInsertCommandIntoCommandBuffer(uint8_t command, SMTPState *state, Flow *f)
664 {
665  SCEnter();
666  void *ptmp;
667 
668  if (state->cmds_cnt >= state->cmds_buffer_len) {
669  int increment = SMTP_COMMAND_BUFFER_STEPS;
670  if ((int)(state->cmds_buffer_len + SMTP_COMMAND_BUFFER_STEPS) > (int)USHRT_MAX) {
671  increment = USHRT_MAX - state->cmds_buffer_len;
672  }
673 
674  ptmp = SCRealloc(state->cmds,
675  sizeof(uint8_t) * (state->cmds_buffer_len + increment));
676  if (ptmp == NULL) {
677  SCFree(state->cmds);
678  state->cmds = NULL;
679  SCLogDebug("SCRealloc failure");
680  return -1;
681  }
682  state->cmds = ptmp;
683 
684  state->cmds_buffer_len += increment;
685  }
686  if (state->cmds_cnt >= 1 &&
687  ((state->cmds[state->cmds_cnt - 1] == SMTP_COMMAND_STARTTLS) ||
688  (state->cmds[state->cmds_cnt - 1] == SMTP_COMMAND_DATA))) {
689  /* decoder event */
691  /* we have to have EHLO, DATA, VRFY, EXPN, TURN, QUIT, NOOP,
692  * STARTTLS as the last command in pipelined mode */
693  }
694 
695  /** \todo decoder event */
696  if ((int)(state->cmds_cnt + 1) > (int)USHRT_MAX) {
697  SCLogDebug("command buffer overflow");
698  return -1;
699  }
700 
701  state->cmds[state->cmds_cnt] = command;
702  state->cmds_cnt++;
703 
704  return 0;
705 }
706 
707 static int SMTPProcessCommandBDAT(SMTPState *state, Flow *f,
708  AppLayerParserState *pstate)
709 {
710  SCEnter();
711 
712  state->bdat_chunk_idx += (state->current_line_len +
714  if (state->bdat_chunk_idx > state->bdat_chunk_len) {
716  /* decoder event */
717  SMTPSetEvent(state, SMTP_DECODER_EVENT_BDAT_CHUNK_LEN_EXCEEDED);
718  SCReturnInt(-1);
719  } else if (state->bdat_chunk_idx == state->bdat_chunk_len) {
721  }
722 
723  SCReturnInt(0);
724 }
725 
726 static void SetMimeEvents(SMTPState *state)
727 {
728  if (state->curr_tx->mime_state->msg == NULL) {
729  return;
730  }
731 
732  /* Generate decoder events */
733  MimeDecEntity *msg = state->curr_tx->mime_state->msg;
734  if (msg->anomaly_flags & ANOM_INVALID_BASE64) {
735  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_INVALID_BASE64);
736  }
737  if (msg->anomaly_flags & ANOM_INVALID_QP) {
738  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_INVALID_QP);
739  }
740  if (msg->anomaly_flags & ANOM_LONG_LINE) {
741  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_LINE);
742  }
743  if (msg->anomaly_flags & ANOM_LONG_ENC_LINE) {
744  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_ENC_LINE);
745  }
746  if (msg->anomaly_flags & ANOM_LONG_HEADER_NAME) {
747  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME);
748  }
749  if (msg->anomaly_flags & ANOM_LONG_HEADER_VALUE) {
750  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE);
751  }
752  if (msg->anomaly_flags & ANOM_MALFORMED_MSG) {
753  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_MALFORMED_MSG);
754  }
755  if (msg->anomaly_flags & ANOM_LONG_BOUNDARY) {
756  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_BOUNDARY_TOO_LONG);
757  }
758  if (msg->anomaly_flags & ANOM_LONG_FILENAME) {
759  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_FILENAME);
760  }
761 }
762 
763 static inline void SMTPTransactionComplete(SMTPState *state)
764 {
765  DEBUG_VALIDATE_BUG_ON(state->curr_tx == NULL);
766  if (state->curr_tx)
767  state->curr_tx->done = 1;
768 }
769 
770 /**
771  * \retval 0 ok
772  * \retval -1 error
773  */
774 static int SMTPProcessCommandDATA(SMTPState *state, Flow *f,
775  AppLayerParserState *pstate)
776 {
777  SCEnter();
778 
780  /* looks like are still waiting for a confirmation from the server */
781  return 0;
782  }
783 
784  if (state->current_line_len == 1 && state->current_line[0] == '.') {
786  /* kinda like a hack. The mail sent in DATA mode, would be
787  * acknowledged with a reply. We insert a dummy command to
788  * the command buffer to be used by the reply handler to match
789  * the reply received */
790  SMTPInsertCommandIntoCommandBuffer(SMTP_COMMAND_DATA_MODE, state, f);
792  /* we use this as the signal that message data is complete. */
793  FileCloseFile(state->files_ts, NULL, 0, 0);
794  } else if (smtp_config.decode_mime &&
795  state->curr_tx->mime_state != NULL) {
796  /* Complete parsing task */
797  int ret = MimeDecParseComplete(state->curr_tx->mime_state);
798  if (ret != MIME_DEC_OK) {
799  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_PARSE_FAILED);
800  SCLogDebug("MimeDecParseComplete() function failed");
801  }
802 
803  /* Generate decoder events */
804  SetMimeEvents(state);
805  }
806  SMTPTransactionComplete(state);
807  SCLogDebug("marked tx as done");
808  } else if (smtp_config.raw_extraction) {
809  // message not over, store the line. This is a substitution of
810  // ProcessDataChunk
811  FileAppendData(state->files_ts, state->current_line,
813  }
814 
815  /* If DATA, then parse out a MIME message */
816  if (state->current_command == SMTP_COMMAND_DATA &&
818 
819  if (smtp_config.decode_mime && state->curr_tx->mime_state != NULL) {
820  int ret = MimeDecParseLine((const uint8_t *) state->current_line,
822  state->curr_tx->mime_state);
823  if (ret != MIME_DEC_OK) {
824  if (ret != MIME_DEC_ERR_STATE) {
825  /* Generate decoder events */
826  SetMimeEvents(state);
827 
828  SCLogDebug("MimeDecParseLine() function returned an error code: %d", ret);
829  SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_PARSE_FAILED);
830  }
831  /* keep the parser in its error state so we can log that,
832  * the parser will reject new data */
833  }
834  }
835  }
836 
837  return 0;
838 }
839 
840 static int SMTPProcessCommandSTARTTLS(SMTPState *state, Flow *f,
841  AppLayerParserState *pstate)
842 {
843  return 0;
844 }
845 
846 static inline bool IsReplyToCommand(const SMTPState *state, const uint8_t cmd)
847 {
848  return (state->cmds_idx < state->cmds_buffer_len &&
849  state->cmds[state->cmds_idx] == cmd);
850 }
851 
852 static int SMTPProcessReply(SMTPState *state, Flow *f,
853  AppLayerParserState *pstate,
854  SMTPThreadCtx *td)
855 {
856  SCEnter();
857 
858  /* Line with just LF */
859  if (state->current_line_len == 0 && state->consumed == 1 &&
860  state->current_line_delimiter_len == 1) {
861  return 0; // to continue processing further
862  }
863 
864  /* the reply code has to contain at least 3 bytes, to hold the 3 digit
865  * reply code */
866  if (state->current_line_len < 3) {
867  /* decoder event */
868  SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY);
869  return -1;
870  }
871 
872  if (state->current_line_len >= 4) {
874  if (state->current_line[3] != '-') {
876  }
877  } else {
878  if (state->current_line[3] == '-') {
880  }
881  }
882  } else {
885  }
886  }
887 
888  /* I don't like this pmq reset here. We'll devise a method later, that
889  * should make the use of the mpm very efficient */
890  PmqReset(td->pmq);
891  int mpm_cnt = mpm_table[SMTP_MPM].Search(smtp_mpm_ctx, td->smtp_mpm_thread_ctx,
892  td->pmq, state->current_line,
893  3);
894  if (mpm_cnt == 0) {
895  /* set decoder event - reply code invalid */
896  SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY);
897  SCLogDebug("invalid reply code %02x %02x %02x",
898  state->current_line[0], state->current_line[1], state->current_line[2]);
899  SCReturnInt(-1);
900  }
901  enum SMTPCode reply_code = smtp_reply_map[td->pmq->rule_id_array[0]].enum_value;
902  SCLogDebug("REPLY: reply_code %u / %s", reply_code,
903  smtp_reply_map[reply_code].enum_name);
904 
905  if (state->cmds_idx == state->cmds_cnt) {
907  /* the first server reply can be a multiline message. Let's
908  * flag the fact that we have seen the first reply only at the end
909  * of a multiline reply
910  */
913  if (reply_code == SMTP_REPLY_220)
914  SCReturnInt(0);
915  else {
916  SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY);
917  SCReturnInt(0);
918  }
919  } else {
920  /* decoder event - unable to match reply with request */
921  SCLogDebug("unable to match reply with request");
922  SCReturnInt(0);
923  }
924  }
925 
926  if (state->cmds_cnt == 0) {
927  /* reply but not a command we have stored, fall through */
928  } else if (IsReplyToCommand(state, SMTP_COMMAND_STARTTLS)) {
929  if (reply_code == SMTP_REPLY_220) {
930  /* we are entering STARRTTLS data mode */
933  if (state->curr_tx) {
934  SMTPTransactionComplete(state);
935  }
936  } else {
937  /* decoder event */
938  SMTPSetEvent(state, SMTP_DECODER_EVENT_TLS_REJECTED);
939  }
940  } else if (IsReplyToCommand(state, SMTP_COMMAND_DATA)) {
941  if (reply_code == SMTP_REPLY_354) {
942  /* Next comes the mail for the DATA command in toserver direction */
944  } else {
945  /* decoder event */
946  SMTPSetEvent(state, SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED);
947  }
948  } else if (IsReplyToCommand(state, SMTP_COMMAND_RSET)) {
949  if (reply_code == SMTP_REPLY_250 && state->curr_tx &&
951  SMTPTransactionComplete(state);
952  }
953  } else {
954  /* we don't care for any other command for now */
955  }
956 
957  /* if it is a multi-line reply, we need to move the index only once for all
958  * the line of the reply. We unset the multiline flag on the last
959  * line of the multiline reply, following which we increment the index */
961  state->cmds_idx++;
962  } else if (state->parser_state & SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
963  /* we check if the server is indicating pipelining support */
964  if (reply_code == SMTP_REPLY_250 && state->current_line_len == 14 &&
965  SCMemcmpLowercase("pipelining", state->current_line+4, 10) == 0) {
967  }
968  }
969 
970  /* if we have matched all the buffered commands, reset the cnt and index */
971  if (state->cmds_idx == state->cmds_cnt) {
972  state->cmds_cnt = 0;
973  state->cmds_idx = 0;
974  }
975 
976  return 0;
977 }
978 
979 static int SMTPParseCommandBDAT(SMTPState *state)
980 {
981  SCEnter();
982 
983  int i = 4;
984  while (i < state->current_line_len) {
985  if (state->current_line[i] != ' ') {
986  break;
987  }
988  i++;
989  }
990  if (i == 4) {
991  /* decoder event */
992  return -1;
993  }
994  if (i == state->current_line_len) {
995  /* decoder event */
996  return -1;
997  }
998  char *endptr = NULL;
999  // copy in temporary null-terminated buffer to call strtoul
1000  char strbuf[24];
1001  int len = 23;
1002  if (state->current_line_len - i < len) {
1003  len = state->current_line_len - i;
1004  }
1005  memcpy(strbuf, (const char *)state->current_line + i, len);
1006  strbuf[len] = '\0';
1007  state->bdat_chunk_len = strtoul((const char *)strbuf, (char **)&endptr, 10);
1008  if ((uint8_t *)endptr == state->current_line + i) {
1009  /* decoder event */
1010  return -1;
1011  }
1012 
1013  return 0;
1014 }
1015 
1016 static int SMTPParseCommandWithParam(SMTPState *state, uint8_t prefix_len, uint8_t **target, uint16_t *target_len)
1017 {
1018  int i = prefix_len + 1;
1019  int spc_i = 0;
1020 
1021  while (i < state->current_line_len) {
1022  if (state->current_line[i] != ' ') {
1023  break;
1024  }
1025  i++;
1026  }
1027 
1028  /* rfc1870: with the size extension the mail from can be followed by an option.
1029  We use the space separator to detect it. */
1030  spc_i = i;
1031  while (spc_i < state->current_line_len) {
1032  if (state->current_line[spc_i] == ' ') {
1033  break;
1034  }
1035  spc_i++;
1036  }
1037 
1038  *target = SCMalloc(spc_i - i + 1);
1039  if (*target == NULL)
1040  return -1;
1041  memcpy(*target, state->current_line + i, spc_i - i);
1042  (*target)[spc_i - i] = '\0';
1043  if (spc_i - i > UINT16_MAX) {
1044  *target_len = UINT16_MAX;
1046  } else {
1047  *target_len = (uint16_t)(spc_i - i);
1048  }
1049 
1050  return 0;
1051 }
1052 
1053 static int SMTPParseCommandHELO(SMTPState *state)
1054 {
1055  if (state->helo) {
1056  SMTPSetEvent(state, SMTP_DECODER_EVENT_DUPLICATE_FIELDS);
1057  return 0;
1058  }
1059  return SMTPParseCommandWithParam(state, 4, &state->helo, &state->helo_len);
1060 }
1061 
1062 static int SMTPParseCommandMAILFROM(SMTPState *state)
1063 {
1064  if (state->curr_tx->mail_from) {
1065  SMTPSetEvent(state, SMTP_DECODER_EVENT_DUPLICATE_FIELDS);
1066  return 0;
1067  }
1068  return SMTPParseCommandWithParam(state, 9,
1069  &state->curr_tx->mail_from,
1070  &state->curr_tx->mail_from_len);
1071 }
1072 
1073 static int SMTPParseCommandRCPTTO(SMTPState *state)
1074 {
1075  uint8_t *rcptto;
1076  uint16_t rcptto_len;
1077 
1078  if (SMTPParseCommandWithParam(state, 7, &rcptto, &rcptto_len) == 0) {
1079  SMTPString *rcptto_str = SMTPStringAlloc();
1080  if (rcptto_str) {
1081  rcptto_str->str = rcptto;
1082  rcptto_str->len = rcptto_len;
1083  TAILQ_INSERT_TAIL(&state->curr_tx->rcpt_to_list, rcptto_str, next);
1084  } else {
1085  SCFree(rcptto);
1086  return -1;
1087  }
1088  } else {
1089  return -1;
1090  }
1091  return 0;
1092 }
1093 
1094 /* consider 'rset' and 'quit' to be part of the existing state */
1095 static int NoNewTx(SMTPState *state)
1096 {
1098  if (state->current_line_len >= 4 &&
1099  SCMemcmpLowercase("rset", state->current_line, 4) == 0) {
1100  return 1;
1101  } else if (state->current_line_len >= 4 &&
1102  SCMemcmpLowercase("quit", state->current_line, 4) == 0) {
1103  return 1;
1104  }
1105  }
1106  return 0;
1107 }
1108 
1109 /* XXX have a better name */
1110 #define rawmsgname "rawmsg"
1112 static int SMTPProcessRequest(SMTPState *state, Flow *f,
1113  AppLayerParserState *pstate)
1114 {
1115  SCEnter();
1116  SMTPTransaction *tx = state->curr_tx;
1117 
1118  /* Line with just LF */
1119  if (state->current_line_len == 0 && state->consumed == 1) {
1120  return 0; // to continue processing further
1121  }
1122 
1123  if (state->curr_tx == NULL || (state->curr_tx->done && !NoNewTx(state))) {
1124  tx = SMTPTransactionCreate();
1125  if (tx == NULL)
1126  return -1;
1127  state->curr_tx = tx;
1128  TAILQ_INSERT_TAIL(&state->tx_list, tx, next);
1129  tx->tx_id = state->tx_cnt++;
1130 
1131  /* keep track of the start of the tx */
1133  StreamTcpReassemblySetMinInspectDepth(f->protoctx, STREAM_TOSERVER,
1135  }
1136 
1137  state->toserver_data_count += (
1138  state->current_line_len +
1140 
1142  SMTPSetEvent(state, SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE);
1143  }
1144 
1145  /* there are 2 commands that can push it into this COMMAND_DATA mode -
1146  * STARTTLS and DATA */
1148  int r = 0;
1149 
1150  if (state->current_line_len >= 8 &&
1151  SCMemcmpLowercase("starttls", state->current_line, 8) == 0) {
1153  } else if (state->current_line_len >= 4 &&
1154  SCMemcmpLowercase("data", state->current_line, 4) == 0) {
1157  if (state->files_ts == NULL)
1158  state->files_ts = FileContainerAlloc();
1159  if (state->files_ts == NULL) {
1160  return -1;
1161  }
1162  if (state->tx_cnt > 1 && !state->curr_tx->done) {
1163  // we did not close the previous tx, set error
1164  SMTPSetEvent(state, SMTP_DECODER_EVENT_UNPARSABLE_CONTENT);
1165  FileCloseFile(state->files_ts, NULL, 0, FILE_TRUNCATED);
1166  tx = SMTPTransactionCreate();
1167  if (tx == NULL)
1168  return -1;
1169  state->curr_tx = tx;
1170  TAILQ_INSERT_TAIL(&state->tx_list, tx, next);
1171  tx->tx_id = state->tx_cnt++;
1172  }
1174  (uint8_t *)rawmsgname, strlen(rawmsgname), NULL, 0,
1176  SMTPNewFile(state->curr_tx, state->files_ts->tail);
1177  }
1178  } else if (smtp_config.decode_mime) {
1179  if (tx->mime_state) {
1180  /* We have 2 chained mails and did not detect the end
1181  * of first one. So we start a new transaction. */
1183  SMTPSetEvent(state, SMTP_DECODER_EVENT_UNPARSABLE_CONTENT);
1184  tx = SMTPTransactionCreate();
1185  if (tx == NULL)
1186  return -1;
1187  state->curr_tx = tx;
1188  TAILQ_INSERT_TAIL(&state->tx_list, tx, next);
1189  tx->tx_id = state->tx_cnt++;
1190  }
1192  if (tx->mime_state == NULL) {
1193  SCLogError(SC_ERR_MEM_ALLOC, "MimeDecInitParser() failed to "
1194  "allocate data");
1195  return MIME_DEC_ERR_MEM;
1196  }
1197 
1198  /* Add new MIME message to end of list */
1199  if (tx->msg_head == NULL) {
1200  tx->msg_head = tx->mime_state->msg;
1201  tx->msg_tail = tx->mime_state->msg;
1202  }
1203  else {
1204  tx->msg_tail->next = tx->mime_state->msg;
1205  tx->msg_tail = tx->mime_state->msg;
1206  }
1207  }
1208  /* Enter immediately data mode without waiting for server reply */
1211  }
1212  } else if (state->current_line_len >= 4 &&
1213  SCMemcmpLowercase("bdat", state->current_line, 4) == 0) {
1214  r = SMTPParseCommandBDAT(state);
1215  if (r == -1) {
1216  SCReturnInt(-1);
1217  }
1220  } else if (state->current_line_len >= 4 &&
1221  ((SCMemcmpLowercase("helo", state->current_line, 4) == 0) ||
1222  SCMemcmpLowercase("ehlo", state->current_line, 4) == 0)) {
1223  r = SMTPParseCommandHELO(state);
1224  if (r == -1) {
1225  SCReturnInt(-1);
1226  }
1228  } else if (state->current_line_len >= 9 &&
1229  SCMemcmpLowercase("mail from", state->current_line, 9) == 0) {
1230  r = SMTPParseCommandMAILFROM(state);
1231  if (r == -1) {
1232  SCReturnInt(-1);
1233  }
1235  } else if (state->current_line_len >= 7 &&
1236  SCMemcmpLowercase("rcpt to", state->current_line, 7) == 0) {
1237  r = SMTPParseCommandRCPTTO(state);
1238  if (r == -1) {
1239  SCReturnInt(-1);
1240  }
1242  } else if (state->current_line_len >= 4 &&
1243  SCMemcmpLowercase("rset", state->current_line, 4) == 0) {
1244  // Resets chunk index in case of connection reuse
1245  state->bdat_chunk_idx = 0;
1247  } else {
1249  }
1250 
1251  /* Every command is inserted into a command buffer, to be matched
1252  * against reply(ies) sent by the server */
1253  if (SMTPInsertCommandIntoCommandBuffer(state->current_command,
1254  state, f) == -1) {
1255  SCReturnInt(-1);
1256  }
1257 
1258  SCReturnInt(r);
1259  }
1260 
1261  switch (state->current_command) {
1262  case SMTP_COMMAND_STARTTLS:
1263  return SMTPProcessCommandSTARTTLS(state, f, pstate);
1264 
1265  case SMTP_COMMAND_DATA:
1266  return SMTPProcessCommandDATA(state, f, pstate);
1267 
1268  case SMTP_COMMAND_BDAT:
1269  return SMTPProcessCommandBDAT(state, f, pstate);
1270 
1271  default:
1272  /* we have nothing to do with any other command at this instant.
1273  * Just let it go through */
1274  SCReturnInt(0);
1275  }
1276 }
1277 
1278 static int SMTPPreProcessCommands(SMTPState *state, Flow *f, AppLayerParserState *pstate)
1279 {
1280  // By this time we should have had the command line parsed
1281  uint8_t *lf_idx = memchr(state->input + state->consumed, 0x0a, state->input_len);
1282  const uint32_t orig_input_len = state->input_len;
1283  // Both DATA and BDAT set SMTP_PARSER_STATE_COMMAND_DATA_MODE, so this while
1284  // loop should be valid for both
1285  while (state->input_len > 0 && (state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1286  uint8_t delim_len = 0;
1287  uint32_t consumed_line = 0;
1288  if (lf_idx == NULL) {
1289  if ((state->input_len == 1 && state->input[state->consumed] == '-') ||
1290  (state->input_len > 1 && state->input[state->consumed] == '-' &&
1291  state->input[state->consumed + 1] == '-')) {
1292  SCLogDebug("possible boundary, yield to getline");
1293  return 1;
1294  }
1295  state->current_line = state->input + state->consumed;
1296  state->consumed = state->input_len;
1297  consumed_line = state->input_len;
1298  } else {
1299  state->current_line = state->input + state->consumed;
1300  ptrdiff_t idx = lf_idx - state->input;
1301  state->consumed = idx + 1;
1302  consumed_line = lf_idx - state->current_line + 1;
1303  if (orig_input_len >= idx && idx > 0 && state->input[idx - 1] == 0x0d) {
1304  delim_len = 2;
1305  } else if (orig_input_len == 1 ||
1306  (orig_input_len >= idx && idx > 0 && state->input[idx - 1] != 0x0d)) {
1307  delim_len = 1;
1308  }
1309  }
1310  state->current_line_delimiter_len = delim_len;
1311  state->current_line_len = consumed_line - delim_len;
1312  state->input_len -= (state->current_line_len + delim_len);
1313  if (SMTPProcessRequest(state, f, pstate) == -1) {
1314  return -1;
1315  }
1316  lf_idx = memchr(state->input + state->consumed, 0x0a, state->input_len);
1317  }
1318  return 0;
1319 }
1320 
1321 static AppLayerResult SMTPParse(uint8_t direction, Flow *f, SMTPState *state,
1322  AppLayerParserState *pstate, StreamSlice stream_slice, SMTPThreadCtx *thread_data)
1323 {
1324  SCEnter();
1325 
1326  const uint8_t *input = StreamSliceGetData(&stream_slice);
1327  uint32_t input_len = StreamSliceGetDataLen(&stream_slice);
1328 
1329  if (input == NULL &&
1330  ((direction == 0 && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TS)) ||
1331  (direction == 1 && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TC)))) {
1333  } else if (input == NULL || input_len == 0) {
1335  }
1336 
1337  state->input = input;
1338  state->orig_input_len = input_len;
1339  state->input_len = input_len;
1340  state->consumed = 0;
1341  state->direction = direction;
1342  if (direction == 0) {
1343  if (((state->current_command == SMTP_COMMAND_DATA) ||
1344  (state->current_command == SMTP_COMMAND_BDAT)) &&
1346  int ret = SMTPPreProcessCommands(state, f, pstate);
1347  if (ret == 0 && state->consumed == state->input_len) {
1349  }
1350  }
1351  }
1352  AppLayerResult res = SMTPGetLine(state);
1353 
1354  /* toserver */
1355  if (direction == 0) {
1356  while (res.status == 0) {
1357  BUG_ON(state->discard_till_lf);
1358  if (!state->discard_till_lf) {
1359  if ((state->current_line_len > 0) && (SMTPProcessRequest(state, f, pstate) == -1))
1361  if (state->current_line_delimiter_len == 0 &&
1363  state->discard_till_lf = true;
1364  state->consumed = state->input_len + 1; // For the newly found LF
1365  SMTPSetEvent(state, SMTP_DECODER_EVENT_TRUNCATED_LINE);
1366  break;
1367  }
1368  res = SMTPGetLine(state);
1369  }
1370  }
1371  if (res.status == 1)
1372  return res;
1373  /* toclient */
1374  } else {
1375  while (res.status == 0) {
1376  BUG_ON(state->discard_till_lf);
1377  if (!state->discard_till_lf) {
1378  if ((state->current_line_len > 0) &&
1379  (SMTPProcessReply(state, f, pstate, thread_data) == -1))
1381  if (state->current_line_delimiter_len == 0 &&
1383  state->discard_till_lf = true;
1384  state->consumed = state->input_len + 1; // For the newly found LF
1385  SMTPSetEvent(state, SMTP_DECODER_EVENT_TRUNCATED_LINE);
1386  break;
1387  }
1388  res = SMTPGetLine(state);
1389  }
1390  }
1391  if (res.status == 1)
1392  return res;
1393  }
1394 
1396 }
1397 
1398 static AppLayerResult SMTPParseClientRecord(Flow *f, void *alstate, AppLayerParserState *pstate,
1399  StreamSlice stream_slice, void *local_data)
1400 {
1401  SCEnter();
1402 
1403  /* first arg 0 is toserver */
1404  return SMTPParse(0, f, alstate, pstate, stream_slice, local_data);
1405 }
1406 
1407 static AppLayerResult SMTPParseServerRecord(Flow *f, void *alstate, AppLayerParserState *pstate,
1408  StreamSlice stream_slice, void *local_data)
1409 {
1410  SCEnter();
1411 
1412  /* first arg 1 is toclient */
1413  return SMTPParse(1, f, alstate, pstate, stream_slice, local_data);
1414 }
1415 
1416 /**
1417  * \internal
1418  * \brief Function to allocate SMTP state memory.
1419  */
1420 void *SMTPStateAlloc(void *orig_state, AppProto proto_orig)
1421 {
1422  SMTPState *smtp_state = SCMalloc(sizeof(SMTPState));
1423  if (unlikely(smtp_state == NULL))
1424  return NULL;
1425  memset(smtp_state, 0, sizeof(SMTPState));
1426 
1427  smtp_state->cmds = SCMalloc(sizeof(uint8_t) *
1429  if (smtp_state->cmds == NULL) {
1430  SCFree(smtp_state);
1431  return NULL;
1432  }
1434 
1435  TAILQ_INIT(&smtp_state->tx_list);
1436 
1437  return smtp_state;
1438 }
1439 
1440 static SMTPString *SMTPStringAlloc(void)
1441 {
1442  SMTPString *smtp_string = SCMalloc(sizeof(SMTPString));
1443  if (unlikely(smtp_string == NULL))
1444  return NULL;
1445  memset(smtp_string, 0, sizeof(SMTPString));
1446 
1447  return smtp_string;
1448 }
1449 
1450 
1451 static void SMTPStringFree(SMTPString *str)
1452 {
1453  if (str->str) {
1454  SCFree(str->str);
1455  }
1456  SCFree(str);
1457 }
1458 
1459 static void *SMTPLocalStorageAlloc(void)
1460 {
1461  /* needed by the mpm */
1462  SMTPThreadCtx *td = SCCalloc(1, sizeof(*td));
1463  if (td == NULL) {
1464  exit(EXIT_FAILURE);
1465  }
1466 
1467  td->pmq = SCCalloc(1, sizeof(*td->pmq));
1468  if (td->pmq == NULL) {
1469  exit(EXIT_FAILURE);
1470  }
1471  PmqSetup(td->pmq);
1472 
1473  td->smtp_mpm_thread_ctx = SCCalloc(1, sizeof(MpmThreadCtx));
1474  if (unlikely(td->smtp_mpm_thread_ctx == NULL)) {
1475  exit(EXIT_FAILURE);
1476  }
1478  return td;
1479 }
1480 
1481 static void SMTPLocalStorageFree(void *ptr)
1482 {
1483  SMTPThreadCtx *td = ptr;
1484  if (td != NULL) {
1485  if (td->pmq != NULL) {
1486  PmqFree(td->pmq);
1487  SCFree(td->pmq);
1488  }
1489 
1490  if (td->smtp_mpm_thread_ctx != NULL) {
1493  }
1494 
1495  SCFree(td);
1496  }
1497 
1498  return;
1499 }
1500 
1501 static void SMTPTransactionFree(SMTPTransaction *tx, SMTPState *state)
1502 {
1503  if (tx->mime_state != NULL) {
1505  }
1506  /* Free list of MIME message recursively */
1508 
1509  if (tx->tx_data.events != NULL)
1511 
1512  if (tx->tx_data.de_state != NULL)
1513  DetectEngineStateFree(tx->tx_data.de_state);
1514 
1515  if (tx->mail_from)
1516  SCFree(tx->mail_from);
1517 
1518  SMTPString *str = NULL;
1519  while ((str = TAILQ_FIRST(&tx->rcpt_to_list))) {
1520  TAILQ_REMOVE(&tx->rcpt_to_list, str, next);
1521  SMTPStringFree(str);
1522  }
1523  SCFree(tx);
1524 }
1525 
1526 /**
1527  * \internal
1528  * \brief Function to free SMTP state memory.
1529  */
1530 static void SMTPStateFree(void *p)
1531 {
1532  SMTPState *smtp_state = (SMTPState *)p;
1533 
1534  if (smtp_state->cmds != NULL) {
1535  SCFree(smtp_state->cmds);
1536  }
1537 
1538  if (smtp_state->helo) {
1539  SCFree(smtp_state->helo);
1540  }
1541 
1542  FileContainerFree(smtp_state->files_ts);
1543 
1544  SMTPTransaction *tx = NULL;
1545  while ((tx = TAILQ_FIRST(&smtp_state->tx_list))) {
1546  TAILQ_REMOVE(&smtp_state->tx_list, tx, next);
1547  SMTPTransactionFree(tx, smtp_state);
1548  }
1549 
1550  SCFree(smtp_state);
1551 
1552  return;
1553 }
1554 
1555 static void SMTPSetMpmState(void)
1556 {
1557  smtp_mpm_ctx = SCMalloc(sizeof(MpmCtx));
1558  if (unlikely(smtp_mpm_ctx == NULL)) {
1559  exit(EXIT_FAILURE);
1560  }
1561  memset(smtp_mpm_ctx, 0, sizeof(MpmCtx));
1562  MpmInitCtx(smtp_mpm_ctx, SMTP_MPM);
1563 
1564  uint32_t i = 0;
1565  for (i = 0; i < sizeof(smtp_reply_map)/sizeof(SCEnumCharMap) - 1; i++) {
1566  SCEnumCharMap *map = &smtp_reply_map[i];
1567  /* The third argument is 3, because reply code is always 3 bytes. */
1568  MpmAddPatternCI(smtp_mpm_ctx, (uint8_t *)map->enum_name, 3,
1569  0 /* defunct */, 0 /* defunct */,
1570  i /* pattern id */, i /* rule id */ , 0 /* no flags */);
1571  }
1572 
1573  mpm_table[SMTP_MPM].Prepare(smtp_mpm_ctx);
1574 
1575 }
1576 
1577 static void SMTPFreeMpmState(void)
1578 {
1579  if (smtp_mpm_ctx != NULL) {
1580  mpm_table[SMTP_MPM].DestroyCtx(smtp_mpm_ctx);
1581  SCFree(smtp_mpm_ctx);
1582  smtp_mpm_ctx = NULL;
1583  }
1584 }
1585 
1586 static int SMTPStateGetEventInfo(const char *event_name,
1587  int *event_id, AppLayerEventType *event_type)
1588 {
1589  *event_id = SCMapEnumNameToValue(event_name, smtp_decoder_event_table);
1590  if (*event_id == -1) {
1591  SCLogError(SC_ERR_INVALID_ENUM_MAP, "event \"%s\" not present in "
1592  "smtp's enum map table.", event_name);
1593  /* yes this is fatal */
1594  return -1;
1595  }
1596 
1597  *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
1598 
1599  return 0;
1600 }
1601 
1602 static int SMTPStateGetEventInfoById(int event_id, const char **event_name,
1603  AppLayerEventType *event_type)
1604 {
1605  *event_name = SCMapEnumValueToName(event_id, smtp_decoder_event_table);
1606  if (*event_name == NULL) {
1607  SCLogError(SC_ERR_INVALID_ENUM_MAP, "event \"%d\" not present in "
1608  "smtp's enum map table.", event_id);
1609  /* yes this is fatal */
1610  return -1;
1611  }
1612 
1613  *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
1614 
1615  return 0;
1616 }
1617 
1618 static int SMTPRegisterPatternsForProtocolDetection(void)
1619 {
1621  "EHLO", 4, 0, STREAM_TOSERVER) < 0)
1622  {
1623  return -1;
1624  }
1626  "HELO", 4, 0, STREAM_TOSERVER) < 0)
1627  {
1628  return -1;
1629  }
1631  "QUIT", 4, 0, STREAM_TOSERVER) < 0)
1632  {
1633  return -1;
1634  }
1635 
1636  return 0;
1637 }
1638 
1639 static void SMTPStateTransactionFree (void *state, uint64_t tx_id)
1640 {
1641  SMTPState *smtp_state = state;
1642  SMTPTransaction *tx = NULL;
1643  TAILQ_FOREACH(tx, &smtp_state->tx_list, next) {
1644  if (tx_id < tx->tx_id)
1645  break;
1646  else if (tx_id > tx->tx_id)
1647  continue;
1648 
1649  if (tx == smtp_state->curr_tx)
1650  smtp_state->curr_tx = NULL;
1651  TAILQ_REMOVE(&smtp_state->tx_list, tx, next);
1652  SMTPTransactionFree(tx, state);
1653  break;
1654  }
1655 
1656 
1657 }
1658 
1659 /** \retval cnt highest tx id */
1660 static uint64_t SMTPStateGetTxCnt(void *state)
1661 {
1662  uint64_t cnt = 0;
1663  SMTPState *smtp_state = state;
1664  if (smtp_state) {
1665  cnt = smtp_state->tx_cnt;
1666  }
1667  SCLogDebug("returning %"PRIu64, cnt);
1668  return cnt;
1669 }
1670 
1671 static void *SMTPStateGetTx(void *state, uint64_t id)
1672 {
1673  SMTPState *smtp_state = state;
1674  if (smtp_state) {
1675  SMTPTransaction *tx = NULL;
1676 
1677  if (smtp_state->curr_tx == NULL)
1678  return NULL;
1679  if (smtp_state->curr_tx->tx_id == id)
1680  return smtp_state->curr_tx;
1681 
1682  TAILQ_FOREACH(tx, &smtp_state->tx_list, next) {
1683  if (tx->tx_id == id)
1684  return tx;
1685  }
1686  }
1687  return NULL;
1688 
1689 }
1690 
1691 static int SMTPStateGetAlstateProgress(void *vtx, uint8_t direction)
1692 {
1693  SMTPTransaction *tx = vtx;
1694  return tx->done;
1695 }
1696 
1697 static FileContainer *SMTPStateGetFiles(void *state, uint8_t direction)
1698 {
1699  if (state == NULL)
1700  return NULL;
1701 
1702  SMTPState *smtp_state = (SMTPState *)state;
1703 
1704  if (direction & STREAM_TOCLIENT) {
1705  SCReturnPtr(NULL, "FileContainer");
1706  } else {
1707  SCLogDebug("smtp_state->files_ts %p", smtp_state->files_ts);
1708  SCReturnPtr(smtp_state->files_ts, "FileContainer");
1709  }
1710 }
1711 
1712 static void SMTPStateTruncate(void *state, uint8_t direction)
1713 {
1714  FileContainer *fc = SMTPStateGetFiles(state, direction);
1715  if (fc != NULL) {
1716  SCLogDebug("truncating stream, closing files in %s direction (container %p)",
1717  direction & STREAM_TOCLIENT ? "STREAM_TOCLIENT" : "STREAM_TOSERVER", fc);
1719  }
1720 }
1721 
1722 static AppLayerTxData *SMTPGetTxData(void *vtx)
1723 {
1724  SMTPTransaction *tx = (SMTPTransaction *)vtx;
1725  return &tx->tx_data;
1726 }
1727 
1728 /**
1729  * \brief Register the SMTP Protocol parser.
1730  */
1732 {
1733  const char *proto_name = "smtp";
1734 
1735  if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
1737  if (SMTPRegisterPatternsForProtocolDetection() < 0 )
1738  return;
1739  } else {
1740  SCLogInfo("Protocol detection and parser disabled for %s protocol.",
1741  proto_name);
1742  return;
1743  }
1744 
1745  if (AppLayerParserConfParserEnabled("tcp", proto_name)) {
1746  AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateAlloc, SMTPStateFree);
1747 
1748  AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_SMTP, STREAM_TOSERVER,
1749  SMTPParseClientRecord);
1750  AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_SMTP, STREAM_TOCLIENT,
1751  SMTPParseServerRecord);
1752 
1753  AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetEventInfo);
1754  AppLayerParserRegisterGetEventInfoById(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetEventInfoById);
1755 
1756  AppLayerParserRegisterLocalStorageFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPLocalStorageAlloc,
1757  SMTPLocalStorageFree);
1758 
1759  AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateTransactionFree);
1760  AppLayerParserRegisterGetFilesFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetFiles);
1761  AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetAlstateProgress);
1762  AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTxCnt);
1763  AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTx);
1764  AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetTxData);
1766  AppLayerParserRegisterTruncateFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateTruncate);
1767  } else {
1768  SCLogInfo("Parsed disabled for %s protocol. Protocol detection"
1769  "still on.", proto_name);
1770  }
1771 
1772  SMTPSetMpmState();
1773 
1774  SMTPConfigure();
1775 
1776 #ifdef UNITTESTS
1778 #endif
1779  return;
1780 }
1781 
1782 /**
1783  * \brief Free memory allocated for global SMTP parser state.
1784  */
1786 {
1787  SMTPFreeMpmState();
1788 }
1789 
1790 /***************************************Unittests******************************/
1791 
1792 #ifdef UNITTESTS
1793 
1794 static void SMTPTestInitConfig(void)
1795 {
1797 
1801 
1803 }
1804 
1805 /*
1806  * \test Test STARTTLS.
1807  */
1808 static int SMTPParserTest01(void)
1809 {
1810  int result = 0;
1811  Flow f;
1812  int r = 0;
1813 
1814  /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
1815  uint8_t welcome_reply[] = {
1816  0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
1817  0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
1818  0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
1819  0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
1820  0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
1821  0x0d, 0x0a
1822  };
1823  uint32_t welcome_reply_len = sizeof(welcome_reply);
1824 
1825  /* EHLO [192.168.0.158]<CR><LF> */
1826  uint8_t request1[] = {
1827  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x5b, 0x31, 0x39,
1828  0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e,
1829  0x31, 0x35, 0x38, 0x5d, 0x0d, 0x0a
1830  };
1831  uint32_t request1_len = sizeof(request1);
1832  /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
1833  * 250-SIZE 35882577<CR><LF>
1834  * 250-8BITMIME<CR><LF>
1835  * 250-STARTTLS<CR><LF>
1836  * 250 ENHANCEDSTATUSCODES<CR><LF>
1837  */
1838  uint8_t reply1[] = {
1839  0x32, 0x35, 0x30, 0x2d, 0x6d, 0x78, 0x2e, 0x67,
1840  0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
1841  0x6d, 0x20, 0x61, 0x74, 0x20, 0x79, 0x6f, 0x75,
1842  0x72, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
1843  0x65, 0x2c, 0x20, 0x5b, 0x31, 0x31, 0x37, 0x2e,
1844  0x31, 0x39, 0x38, 0x2e, 0x31, 0x31, 0x35, 0x2e,
1845  0x35, 0x30, 0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30,
1846  0x2d, 0x53, 0x49, 0x5a, 0x45, 0x20, 0x33, 0x35,
1847  0x38, 0x38, 0x32, 0x35, 0x37, 0x37, 0x0d, 0x0a,
1848  0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49, 0x54,
1849  0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35,
1850  0x30, 0x2d, 0x53, 0x54, 0x41, 0x52, 0x54, 0x54,
1851  0x4c, 0x53, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20,
1852  0x45, 0x4e, 0x48, 0x41, 0x4e, 0x43, 0x45, 0x44,
1853  0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x43, 0x4f,
1854  0x44, 0x45, 0x53, 0x0d, 0x0a
1855  };
1856  uint32_t reply1_len = sizeof(reply1);
1857 
1858  /* STARTTLS<CR><LF> */
1859  uint8_t request2[] = {
1860  0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
1861  0x0d, 0x0a
1862  };
1863  uint32_t request2_len = sizeof(request2);
1864  /* 220 2.0.0 Ready to start TLS<CR><LF> */
1865  uint8_t reply2[] = {
1866  0x32, 0x32, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
1867  0x30, 0x20, 0x52, 0x65, 0x61, 0x64, 0x79, 0x20,
1868  0x74, 0x6f, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74,
1869  0x20, 0x54, 0x4c, 0x53, 0x0d, 0x0a
1870  };
1871  uint32_t reply2_len = sizeof(reply2);
1872 
1873  TcpSession ssn;
1875 
1876  memset(&f, 0, sizeof(f));
1877  memset(&ssn, 0, sizeof(ssn));
1878 
1879  FLOW_INITIALIZE(&f);
1880  f.protoctx = (void *)&ssn;
1881  f.proto = IPPROTO_TCP;
1882  f.alproto = ALPROTO_SMTP;
1883 
1884  StreamTcpInitConfig(true);
1885  SMTPTestInitConfig();
1886 
1887  FLOWLOCK_WRLOCK(&f);
1888  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
1889  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
1890  if (r != 0) {
1891  printf("smtp check returned %" PRId32 ", expected 0: ", r);
1892  FLOWLOCK_UNLOCK(&f);
1893  goto end;
1894  }
1895  FLOWLOCK_UNLOCK(&f);
1896  SMTPState *smtp_state = f.alstate;
1897  if (smtp_state == NULL) {
1898  printf("no smtp state: ");
1899  goto end;
1900  }
1901  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
1903  printf("smtp parser in inconsistent state\n");
1904  goto end;
1905  }
1906 
1907  FLOWLOCK_WRLOCK(&f);
1908  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
1909  STREAM_TOSERVER, request1, request1_len);
1910  if (r != 0) {
1911  printf("smtp check returned %" PRId32 ", expected 0: ", r);
1912  FLOWLOCK_UNLOCK(&f);
1913  goto end;
1914  }
1915  FLOWLOCK_UNLOCK(&f);
1916  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
1917  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1919  printf("smtp parser in inconsistent state\n");
1920  goto end;
1921  }
1922 
1923  FLOWLOCK_WRLOCK(&f);
1924  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
1925  STREAM_TOCLIENT, reply1, reply1_len);
1926  if (r != 0) {
1927  printf("smtp check returned %" PRId32 ", expected 0: ", r);
1928  FLOWLOCK_UNLOCK(&f);
1929  goto end;
1930  }
1931  FLOWLOCK_UNLOCK(&f);
1932  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
1934  printf("smtp parser in inconsistent state\n");
1935  goto end;
1936  }
1937 
1938  FLOWLOCK_WRLOCK(&f);
1939  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
1940  STREAM_TOSERVER, request2, request2_len);
1941  if (r != 0) {
1942  printf("smtp check returned %" PRId32 ", expected 0: ", r);
1943  FLOWLOCK_UNLOCK(&f);
1944  goto end;
1945  }
1946  FLOWLOCK_UNLOCK(&f);
1947  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
1948  smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS ||
1950  printf("smtp parser in inconsistent state\n");
1951  goto end;
1952  }
1953 
1954  FLOWLOCK_WRLOCK(&f);
1955  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
1956  STREAM_TOCLIENT, reply2, reply2_len);
1957  if (r != 0) {
1958  printf("smtp check returned %" PRId32 ", expected 0: ", r);
1959  FLOWLOCK_UNLOCK(&f);
1960  goto end;
1961  }
1962  FLOWLOCK_UNLOCK(&f);
1963  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
1964  smtp_state->parser_state !=
1966  printf("smtp parser in inconsistent state\n");
1967  goto end;
1968  }
1969 
1970  if (!FlowChangeProto(&f)) {
1971  goto end;
1972  }
1973 
1974  result = 1;
1975 end:
1976  if (alp_tctx != NULL)
1978  StreamTcpFreeConfig(true);
1979  FLOW_DESTROY(&f);
1980  return result;
1981 }
1982 
1983 /**
1984  * \test Test multiple DATA commands(full mail transactions).
1985  */
1986 static int SMTPParserTest02(void)
1987 {
1988  int result = 0;
1989  Flow f;
1990  int r = 0;
1991 
1992  /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
1993  uint8_t welcome_reply[] = {
1994  0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
1995  0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
1996  0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
1997  0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
1998  0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
1999  0x0d, 0x0a
2000  };
2001  uint32_t welcome_reply_len = sizeof(welcome_reply);
2002 
2003  /* EHLO boo.com<CR><LF> */
2004  uint8_t request1[] = {
2005  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
2006  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
2007  };
2008  uint32_t request1_len = sizeof(request1);
2009  /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
2010  * 250-SIZE 35882577<CR><LF>
2011  * 250-8BITMIME<CR><LF>
2012  * 250-STARTTLS<CR><LF>
2013  * 250 ENHANCEDSTATUSCODES<CR><LF>
2014  */
2015  uint8_t reply1[] = {
2016  0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
2017  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2018  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2019  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
2020  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
2021  0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
2022  0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
2023  0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
2024  0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
2025  0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
2026  0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
2027  0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
2028  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
2029  0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
2030  0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
2031  };
2032  uint32_t reply1_len = sizeof(reply1);
2033 
2034  /* MAIL FROM:asdff@asdf.com<CR><LF> */
2035  uint8_t request2[] = {
2036  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
2037  0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
2038  0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
2039  0x0d, 0x0a
2040  };
2041  uint32_t request2_len = sizeof(request2);
2042  /* 250 2.1.0 Ok<CR><LF> */
2043  uint8_t reply2[] = {
2044  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2045  0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2046  };
2047  uint32_t reply2_len = sizeof(reply2);
2048 
2049  /* RCPT TO:bimbs@gmail.com<CR><LF> */
2050  uint8_t request3[] = {
2051  0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
2052  0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
2053  0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
2054  0x0a
2055  };
2056  uint32_t request3_len = sizeof(request3);
2057  /* 250 2.1.5 Ok<CR><LF> */
2058  uint8_t reply3[] = {
2059  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2060  0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2061  };
2062  uint32_t reply3_len = sizeof(reply3);
2063 
2064  /* DATA<CR><LF> */
2065  uint8_t request4[] = {
2066  0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
2067  };
2068  uint32_t request4_len = sizeof(request4);
2069  /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
2070  uint8_t reply4[] = {
2071  0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
2072  0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
2073  0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
2074  0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
2075  0x4c, 0x46, 0x3e, 0x0d, 0x0a
2076  };
2077  uint32_t reply4_len = sizeof(reply4);
2078 
2079  /* FROM:asdff@asdf.com<CR><LF> */
2080  uint8_t request5_1[] = {
2081  0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
2082  0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
2083  0x63, 0x6f, 0x6d, 0x0d, 0x0a
2084  };
2085  uint32_t request5_1_len = sizeof(request5_1);
2086  /* TO:bimbs@gmail.com<CR><LF> */
2087  uint8_t request5_2[] = {
2088  0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73,
2089  0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63,
2090  0x6f, 0x6d, 0x0d, 0x0a
2091  };
2092  uint32_t request5_2_len = sizeof(request5_2);
2093  /* <CR><LF> */
2094  uint8_t request5_3[] = {
2095  0x0d, 0x0a
2096  };
2097  uint32_t request5_3_len = sizeof(request5_3);
2098  /* this is test mail1<CR><LF> */
2099  uint8_t request5_4[] = {
2100  0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
2101  0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x69,
2102  0x6c, 0x31, 0x0d, 0x0a
2103  };
2104  uint32_t request5_4_len = sizeof(request5_4);
2105  /* .<CR><LF> */
2106  uint8_t request5_5[] = {
2107  0x2e, 0x0d, 0x0a
2108  };
2109  uint32_t request5_5_len = sizeof(request5_5);
2110  /* 250 2.0.0 Ok: queued as 6A1AF20BF2<CR><LF> */
2111  uint8_t reply5[] = {
2112  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
2113  0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
2114  0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
2115  0x36, 0x41, 0x31, 0x41, 0x46, 0x32, 0x30, 0x42,
2116  0x46, 0x32, 0x0d, 0x0a
2117  };
2118  uint32_t reply5_len = sizeof(reply5);
2119 
2120  /* MAIL FROM:asdfg@asdf.com<CR><LF> */
2121  uint8_t request6[] = {
2122  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
2123  0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x67, 0x40,
2124  0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
2125  0x0d, 0x0a
2126  };
2127  uint32_t request6_len = sizeof(request6);
2128  /* 250 2.1.0 Ok<CR><LF> */
2129  uint8_t reply6[] = {
2130  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2131  0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2132  };
2133  uint32_t reply6_len = sizeof(reply6);
2134 
2135  /* RCPT TO:bimbs@gmail.com<CR><LF> */
2136  uint8_t request7[] = {
2137  0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
2138  0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
2139  0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
2140  0x0a
2141  };
2142  uint32_t request7_len = sizeof(request7);
2143  /* 250 2.1.5 Ok<CR><LF> */
2144  uint8_t reply7[] = {
2145  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2146  0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2147  };
2148  uint32_t reply7_len = sizeof(reply7);
2149 
2150  /* DATA<CR><LF> */
2151  uint8_t request8[] = {
2152  0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
2153  };
2154  uint32_t request8_len = sizeof(request8);
2155  /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
2156  uint8_t reply8[] = {
2157  0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
2158  0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
2159  0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
2160  0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
2161  0x4c, 0x46, 0x3e, 0x0d, 0x0a
2162  };
2163  uint32_t reply8_len = sizeof(reply8);
2164 
2165  /* FROM:asdfg@gmail.com<CR><LF> */
2166  uint8_t request9_1[] = {
2167  0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
2168  0x66, 0x67, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c,
2169  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
2170  };
2171  uint32_t request9_1_len = sizeof(request9_1);
2172  /* TO:bimbs@gmail.com<CR><LF> */
2173  uint8_t request9_2[] = {
2174  0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73,
2175  0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63,
2176  0x6f, 0x6d, 0x0d, 0x0a
2177  };
2178  uint32_t request9_2_len = sizeof(request9_2);
2179  /* <CR><LF> */
2180  uint8_t request9_3[] = {
2181  0x0d, 0x0a
2182  };
2183  uint32_t request9_3_len = sizeof(request9_3);
2184  /* this is test mail2<CR><LF> */
2185  uint8_t request9_4[] = {
2186  0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
2187  0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x69,
2188  0x6c, 0x32, 0x0d, 0x0a
2189  };
2190  uint32_t request9_4_len = sizeof(request9_4);
2191  /* .<CR><LF> */
2192  uint8_t request9_5[] = {
2193  0x2e, 0x0d, 0x0a
2194  };
2195  uint32_t request9_5_len = sizeof(request9_5);
2196  /* 250 2.0.0 Ok: queued as 28CFF20BF2<CR><LF> */
2197  uint8_t reply9[] = {
2198  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
2199  0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
2200  0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
2201  0x32, 0x38, 0x43, 0x46, 0x46, 0x32, 0x30, 0x42,
2202  0x46, 0x32, 0x0d, 0x0a
2203  };
2204  uint32_t reply9_len = sizeof(reply9);
2205 
2206  /* QUIT<CR><LF> */
2207  uint8_t request10[] = {
2208  0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
2209  };
2210  uint32_t request10_len = sizeof(request10);
2211  /* 221 2.0.0 Bye<CR><LF> */
2212  uint8_t reply10[] = {
2213  0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
2214  0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
2215  };
2216  uint32_t reply10_len = sizeof(reply10);
2217 
2218  TcpSession ssn;
2220 
2221  memset(&f, 0, sizeof(f));
2222  memset(&ssn, 0, sizeof(ssn));
2223 
2224  FLOW_INITIALIZE(&f);
2225  f.protoctx = (void *)&ssn;
2226  f.proto = IPPROTO_TCP;
2227  f.alproto = ALPROTO_SMTP;
2228 
2229  StreamTcpInitConfig(true);
2230  SMTPTestInitConfig();
2231 
2232  FLOWLOCK_WRLOCK(&f);
2233  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2234  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
2235  if (r != 0) {
2236  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2237  FLOWLOCK_UNLOCK(&f);
2238  goto end;
2239  }
2240  FLOWLOCK_UNLOCK(&f);
2241  SMTPState *smtp_state = f.alstate;
2242  if (smtp_state == NULL) {
2243  printf("no smtp state: ");
2244  goto end;
2245  }
2246  if (smtp_state->input_len != 0 ||
2247  smtp_state->cmds_cnt != 0 ||
2248  smtp_state->cmds_idx != 0 ||
2250  printf("smtp parser in inconsistent state\n");
2251  goto end;
2252  }
2253 
2254  FLOWLOCK_WRLOCK(&f);
2255  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2256  STREAM_TOSERVER, request1, request1_len);
2257  if (r != 0) {
2258  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2259  FLOWLOCK_UNLOCK(&f);
2260  goto end;
2261  }
2262  FLOWLOCK_UNLOCK(&f);
2263  if (smtp_state->input_len != 0 ||
2264  smtp_state->cmds_cnt != 1 ||
2265  smtp_state->cmds_idx != 0 ||
2266  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2268  printf("smtp parser in inconsistent state\n");
2269  goto end;
2270  }
2271 
2272  FLOWLOCK_WRLOCK(&f);
2273  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2274  STREAM_TOCLIENT, reply1, reply1_len);
2275  if (r != 0) {
2276  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2277  FLOWLOCK_UNLOCK(&f);
2278  goto end;
2279  }
2280  FLOWLOCK_UNLOCK(&f);
2281  if (smtp_state->input_len != 0 ||
2282  smtp_state->cmds_cnt != 0 ||
2283  smtp_state->cmds_idx != 0 ||
2285  printf("smtp parser in inconsistent state\n");
2286  goto end;
2287  }
2288 
2289  FLOWLOCK_WRLOCK(&f);
2290  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2291  STREAM_TOSERVER, request2, request2_len);
2292  if (r != 0) {
2293  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2294  FLOWLOCK_UNLOCK(&f);
2295  goto end;
2296  }
2297  FLOWLOCK_UNLOCK(&f);
2298  if (smtp_state->input_len != 0 ||
2299  smtp_state->cmds_cnt != 1 ||
2300  smtp_state->cmds_idx != 0 ||
2301  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2303  printf("smtp parser in inconsistent state\n");
2304  goto end;
2305  }
2306 
2307  FLOWLOCK_WRLOCK(&f);
2308  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2309  STREAM_TOCLIENT, reply2, reply2_len);
2310  if (r != 0) {
2311  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2312  FLOWLOCK_UNLOCK(&f);
2313  goto end;
2314  }
2315  FLOWLOCK_UNLOCK(&f);
2316  if (smtp_state->input_len != 0 ||
2317  smtp_state->cmds_cnt != 0 ||
2318  smtp_state->cmds_idx != 0 ||
2320  printf("smtp parser in inconsistent state\n");
2321  goto end;
2322  }
2323 
2324  FLOWLOCK_WRLOCK(&f);
2325  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2326  STREAM_TOSERVER, request3, request3_len);
2327  if (r != 0) {
2328  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2329  FLOWLOCK_UNLOCK(&f);
2330  goto end;
2331  }
2332  FLOWLOCK_UNLOCK(&f);
2333  if (smtp_state->input_len != 0 ||
2334  smtp_state->cmds_cnt != 1 ||
2335  smtp_state->cmds_idx != 0 ||
2336  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2338  printf("smtp parser in inconsistent state\n");
2339  goto end;
2340  }
2341 
2342  FLOWLOCK_WRLOCK(&f);
2343  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2344  STREAM_TOCLIENT, reply3, reply3_len);
2345  if (r != 0) {
2346  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2347  FLOWLOCK_UNLOCK(&f);
2348  goto end;
2349  }
2350  FLOWLOCK_UNLOCK(&f);
2351  if (smtp_state->input_len != 0 ||
2352  smtp_state->cmds_cnt != 0 ||
2353  smtp_state->cmds_idx != 0 ||
2355  printf("smtp parser in inconsistent state\n");
2356  goto end;
2357  }
2358 
2359  FLOWLOCK_WRLOCK(&f);
2360  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2361  STREAM_TOSERVER, request4, request4_len);
2362  if (r != 0) {
2363  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2364  FLOWLOCK_UNLOCK(&f);
2365  goto end;
2366  }
2367  FLOWLOCK_UNLOCK(&f);
2368  if (smtp_state->input_len != 0 ||
2369  smtp_state->cmds_cnt != 1 ||
2370  smtp_state->cmds_idx != 0 ||
2371  smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
2373  printf("smtp parser in inconsistent state\n");
2374  goto end;
2375  }
2376 
2377  FLOWLOCK_WRLOCK(&f);
2378  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2379  STREAM_TOCLIENT, reply4, reply4_len);
2380  if (r != 0) {
2381  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2382  FLOWLOCK_UNLOCK(&f);
2383  goto end;
2384  }
2385  FLOWLOCK_UNLOCK(&f);
2386  if (smtp_state->input_len != 0 ||
2387  smtp_state->cmds_cnt != 0 ||
2388  smtp_state->cmds_idx != 0 ||
2391  printf("smtp parser in inconsistent state\n");
2392  goto end;
2393  }
2394 
2395  FLOWLOCK_WRLOCK(&f);
2396  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2397  STREAM_TOSERVER, request5_1, request5_1_len);
2398  if (r != 0) {
2399  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2400  FLOWLOCK_UNLOCK(&f);
2401  goto end;
2402  }
2403  FLOWLOCK_UNLOCK(&f);
2404  if (smtp_state->input_len != 0 ||
2405  smtp_state->cmds_cnt != 0 ||
2406  smtp_state->cmds_idx != 0 ||
2409 
2410  printf("smtp parser in inconsistent state\n");
2411  goto end;
2412  }
2413 
2414  FLOWLOCK_WRLOCK(&f);
2415  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2416  STREAM_TOSERVER, request5_2, request5_2_len);
2417  if (r != 0) {
2418  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2419  FLOWLOCK_UNLOCK(&f);
2420  goto end;
2421  }
2422  FLOWLOCK_UNLOCK(&f);
2423  if (smtp_state->input_len != 0 ||
2424  smtp_state->cmds_cnt != 0 ||
2425  smtp_state->cmds_idx != 0 ||
2428 
2429  printf("smtp parser in inconsistent state\n");
2430  goto end;
2431  }
2432 
2433  FLOWLOCK_WRLOCK(&f);
2434  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2435  STREAM_TOSERVER, request5_3, request5_3_len);
2436  if (r != 0) {
2437  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2438  FLOWLOCK_UNLOCK(&f);
2439  goto end;
2440  }
2441  FLOWLOCK_UNLOCK(&f);
2442  if (smtp_state->input_len != 0 ||
2443  smtp_state->cmds_cnt != 0 ||
2444  smtp_state->cmds_idx != 0 ||
2447 
2448  printf("smtp parser in inconsistent state\n");
2449  goto end;
2450  }
2451 
2452  FLOWLOCK_WRLOCK(&f);
2453  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2454  STREAM_TOSERVER, request5_4, request5_4_len);
2455  if (r != 0) {
2456  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2457  FLOWLOCK_UNLOCK(&f);
2458  goto end;
2459  }
2460  FLOWLOCK_UNLOCK(&f);
2461  if (smtp_state->input_len != 0 ||
2462  smtp_state->cmds_cnt != 0 ||
2463  smtp_state->cmds_idx != 0 ||
2466 
2467  printf("smtp parser in inconsistent state\n");
2468  goto end;
2469  }
2470 
2471  FLOWLOCK_WRLOCK(&f);
2472  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2473  STREAM_TOSERVER, request5_5, request5_5_len);
2474  if (r != 0) {
2475  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2476  FLOWLOCK_UNLOCK(&f);
2477  goto end;
2478  }
2479  FLOWLOCK_UNLOCK(&f);
2480  if (smtp_state->input_len != 0 ||
2481  smtp_state->cmds_cnt != 1 ||
2482  smtp_state->cmds_idx != 0 ||
2483  smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
2485  printf("smtp parser in inconsistent state\n");
2486  goto end;
2487  }
2488 
2489  FLOWLOCK_WRLOCK(&f);
2490  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2491  STREAM_TOCLIENT, reply5, reply5_len);
2492  if (r != 0) {
2493  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2494  FLOWLOCK_UNLOCK(&f);
2495  goto end;
2496  }
2497  FLOWLOCK_UNLOCK(&f);
2498  if (smtp_state->input_len != 0 ||
2499  smtp_state->cmds_cnt != 0 ||
2500  smtp_state->cmds_idx != 0 ||
2502  printf("smtp parser in inconsistent state\n");
2503  goto end;
2504  }
2505 
2506  FLOWLOCK_WRLOCK(&f);
2507  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2508  STREAM_TOSERVER, request6, request6_len);
2509  if (r != 0) {
2510  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2511  FLOWLOCK_UNLOCK(&f);
2512  goto end;
2513  }
2514  FLOWLOCK_UNLOCK(&f);
2515  if (smtp_state->input_len != 0 ||
2516  smtp_state->cmds_cnt != 1 ||
2517  smtp_state->cmds_idx != 0 ||
2518  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2520  printf("smtp parser in inconsistent state\n");
2521  goto end;
2522  }
2523 
2524  FLOWLOCK_WRLOCK(&f);
2525  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2526  STREAM_TOCLIENT, reply6, reply6_len);
2527  if (r != 0) {
2528  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2529  FLOWLOCK_UNLOCK(&f);
2530  goto end;
2531  }
2532  FLOWLOCK_UNLOCK(&f);
2533  if (smtp_state->input_len != 0 ||
2534  smtp_state->cmds_cnt != 0 ||
2535  smtp_state->cmds_idx != 0 ||
2537  printf("smtp parser in inconsistent state\n");
2538  goto end;
2539  }
2540 
2541  FLOWLOCK_WRLOCK(&f);
2542  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2543  STREAM_TOSERVER, request7, request7_len);
2544  if (r != 0) {
2545  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2546  FLOWLOCK_UNLOCK(&f);
2547  goto end;
2548  }
2549  FLOWLOCK_UNLOCK(&f);
2550  if (smtp_state->input_len != 0 ||
2551  smtp_state->cmds_cnt != 1 ||
2552  smtp_state->cmds_idx != 0 ||
2553  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2555  printf("smtp parser in inconsistent state\n");
2556  goto end;
2557  }
2558 
2559  FLOWLOCK_WRLOCK(&f);
2560  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2561  STREAM_TOCLIENT, reply7, reply7_len);
2562  if (r != 0) {
2563  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2564  FLOWLOCK_UNLOCK(&f);
2565  goto end;
2566  }
2567  FLOWLOCK_UNLOCK(&f);
2568  if (smtp_state->input_len != 0 ||
2569  smtp_state->cmds_cnt != 0 ||
2570  smtp_state->cmds_idx != 0 ||
2572  printf("smtp parser in inconsistent state\n");
2573  goto end;
2574  }
2575 
2576  FLOWLOCK_WRLOCK(&f);
2577  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2578  STREAM_TOSERVER, request8, request8_len);
2579  if (r != 0) {
2580  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2581  FLOWLOCK_UNLOCK(&f);
2582  goto end;
2583  }
2584  FLOWLOCK_UNLOCK(&f);
2585  if (smtp_state->input_len != 0 ||
2586  smtp_state->cmds_cnt != 1 ||
2587  smtp_state->cmds_idx != 0 ||
2588  smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
2590  printf("smtp parser in inconsistent state\n");
2591  goto end;
2592  }
2593 
2594  FLOWLOCK_WRLOCK(&f);
2595  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2596  STREAM_TOCLIENT, reply8, reply8_len);
2597  if (r != 0) {
2598  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2599  FLOWLOCK_UNLOCK(&f);
2600  goto end;
2601  }
2602  FLOWLOCK_UNLOCK(&f);
2603  if (smtp_state->input_len != 0 ||
2604  smtp_state->cmds_cnt != 0 ||
2605  smtp_state->cmds_idx != 0 ||
2608  printf("smtp parser in inconsistent state\n");
2609  goto end;
2610  }
2611 
2612  FLOWLOCK_WRLOCK(&f);
2613  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2614  STREAM_TOSERVER, request9_1, request9_1_len);
2615  if (r != 0) {
2616  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2617  FLOWLOCK_UNLOCK(&f);
2618  goto end;
2619  }
2620  FLOWLOCK_UNLOCK(&f);
2621  if (smtp_state->input_len != 0 ||
2622  smtp_state->cmds_cnt != 0 ||
2623  smtp_state->cmds_idx != 0 ||
2626 
2627  printf("smtp parser in inconsistent state\n");
2628  goto end;
2629  }
2630 
2631  FLOWLOCK_WRLOCK(&f);
2632  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2633  STREAM_TOSERVER, request9_2, request9_2_len);
2634  if (r != 0) {
2635  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2636  FLOWLOCK_UNLOCK(&f);
2637  goto end;
2638  }
2639  FLOWLOCK_UNLOCK(&f);
2640  if (smtp_state->input_len != 0 ||
2641  smtp_state->cmds_cnt != 0 ||
2642  smtp_state->cmds_idx != 0 ||
2645 
2646  printf("smtp parser in inconsistent state\n");
2647  goto end;
2648  }
2649 
2650  FLOWLOCK_WRLOCK(&f);
2651  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2652  STREAM_TOSERVER, request9_3, request9_3_len);
2653  if (r != 0) {
2654  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2655  FLOWLOCK_UNLOCK(&f);
2656  goto end;
2657  }
2658  FLOWLOCK_UNLOCK(&f);
2659  if (smtp_state->input_len != 0 ||
2660  smtp_state->cmds_cnt != 0 ||
2661  smtp_state->cmds_idx != 0 ||
2664 
2665  printf("smtp parser in inconsistent state\n");
2666  goto end;
2667  }
2668 
2669  FLOWLOCK_WRLOCK(&f);
2670  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2671  STREAM_TOSERVER, request9_4, request9_4_len);
2672  if (r != 0) {
2673  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2674  FLOWLOCK_UNLOCK(&f);
2675  goto end;
2676  }
2677  FLOWLOCK_UNLOCK(&f);
2678  if (smtp_state->input_len != 0 ||
2679  smtp_state->cmds_cnt != 0 ||
2680  smtp_state->cmds_idx != 0 ||
2683 
2684  printf("smtp parser in inconsistent state\n");
2685  goto end;
2686  }
2687 
2688  FLOWLOCK_WRLOCK(&f);
2689  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2690  STREAM_TOSERVER, request9_5, request9_5_len);
2691  if (r != 0) {
2692  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2693  FLOWLOCK_UNLOCK(&f);
2694  goto end;
2695  }
2696  FLOWLOCK_UNLOCK(&f);
2697  if (smtp_state->input_len != 0 ||
2698  smtp_state->cmds_cnt != 1 ||
2699  smtp_state->cmds_idx != 0 ||
2700  smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
2702  printf("smtp parser in inconsistent state\n");
2703  goto end;
2704  }
2705 
2706  FLOWLOCK_WRLOCK(&f);
2707  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2708  STREAM_TOCLIENT, reply9, reply9_len);
2709  if (r != 0) {
2710  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2711  FLOWLOCK_UNLOCK(&f);
2712  goto end;
2713  }
2714  FLOWLOCK_UNLOCK(&f);
2715  if (smtp_state->input_len != 0 ||
2716  smtp_state->cmds_cnt != 0 ||
2717  smtp_state->cmds_idx != 0 ||
2719  printf("smtp parser in inconsistent state\n");
2720  goto end;
2721  }
2722 
2723  FLOWLOCK_WRLOCK(&f);
2724  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2725  STREAM_TOSERVER, request10, request10_len);
2726  if (r != 0) {
2727  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2728  FLOWLOCK_UNLOCK(&f);
2729  goto end;
2730  }
2731  FLOWLOCK_UNLOCK(&f);
2732  if (smtp_state->input_len != 0 ||
2733  smtp_state->cmds_cnt != 1 ||
2734  smtp_state->cmds_idx != 0 ||
2735  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2737  printf("smtp parser in inconsistent state\n");
2738  goto end;
2739  }
2740 
2741  FLOWLOCK_WRLOCK(&f);
2742  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2743  STREAM_TOCLIENT, reply10, reply10_len);
2744  if (r != 0) {
2745  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2746  FLOWLOCK_UNLOCK(&f);
2747  goto end;
2748  }
2749  FLOWLOCK_UNLOCK(&f);
2750  if (smtp_state->input_len != 0 ||
2751  smtp_state->cmds_cnt != 0 ||
2752  smtp_state->cmds_idx != 0 ||
2754  printf("smtp parser in inconsistent state\n");
2755  goto end;
2756  }
2757 
2758  result = 1;
2759 end:
2760  if (alp_tctx != NULL)
2762  StreamTcpFreeConfig(true);
2763  FLOW_DESTROY(&f);
2764  return result;
2765 }
2766 
2767 /**
2768  * \test Testing parsing pipelined commands.
2769  */
2770 static int SMTPParserTest03(void)
2771 {
2772  int result = 0;
2773  Flow f;
2774  int r = 0;
2775 
2776  /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
2777  uint8_t welcome_reply[] = {
2778  0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
2779  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2780  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2781  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
2782  0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
2783  0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
2784  };
2785  uint32_t welcome_reply_len = sizeof(welcome_reply);
2786 
2787  /* EHLO boo.com<CR><LF> */
2788  uint8_t request1[] = {
2789  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
2790  0x2e, 0x63, 0x6f, 0x6d, 0x0a
2791  };
2792  uint32_t request1_len = sizeof(request1);
2793  /* 250-poona_slack_vm1.localdomain<CR><LF>
2794  * 250-PIPELINING<CR><LF>
2795  * 250-SIZE 10240000<CR><LF>
2796  * 250-VRFY<CR><LF>
2797  * 250-ETRN<CR><LF>
2798  * 250-ENHANCEDSTATUSCODES<CR><LF>
2799  * 250-8BITMIME<CR><LF>
2800  * 250 DSN<CR><LF>
2801  */
2802  uint8_t reply1[] = {
2803  0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
2804  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2805  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2806  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
2807  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
2808  0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
2809  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
2810  0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
2811  0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
2812  0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
2813  0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
2814  0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
2815  0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
2816  0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
2817  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
2818  0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
2819  0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
2820  };
2821  uint32_t reply1_len = sizeof(reply1);
2822 
2823  /* MAIL FROM:pbsf@asdfs.com<CR><LF>
2824  * RCPT TO:pbsf@asdfs.com<CR><LF>
2825  * DATA<CR><LF>
2826  * Immediate data
2827  */
2828  uint8_t request2[] = {
2829  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
2830  0x4d, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
2831  0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
2832  0x0d, 0x0a, 0x52, 0x43, 0x50, 0x54, 0x20, 0x54,
2833  0x4f, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
2834  0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
2835  0x0d, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a,
2836  0x49, 0x6d, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74,
2837  0x65, 0x20, 0x64, 0x61, 0x74, 0x61, 0x0d, 0x0a,
2838  };
2839  uint32_t request2_len = sizeof(request2);
2840  /* 250 2.1.0 Ok<CR><LF>
2841  * 250 2.1.5 Ok<CR><LF>
2842  * 354 End data with <CR><LF>.<CR><LF>|<CR><LF>|
2843  */
2844  uint8_t reply2[] = {
2845  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2846  0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a, 0x32, 0x35,
2847  0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, 0x35, 0x20,
2848  0x4f, 0x6b, 0x0d, 0x0a, 0x33, 0x35, 0x34, 0x20,
2849  0x45, 0x6e, 0x64, 0x20, 0x64, 0x61, 0x74, 0x61,
2850  0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x3c, 0x43,
2851  0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x2e, 0x3c,
2852  0x43, 0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x0d,
2853  0x0a
2854  };
2855  uint32_t reply2_len = sizeof(reply2);
2856 
2857  TcpSession ssn;
2859 
2860  memset(&f, 0, sizeof(f));
2861  memset(&ssn, 0, sizeof(ssn));
2862 
2863  FLOW_INITIALIZE(&f);
2864  f.protoctx = (void *)&ssn;
2865  f.proto = IPPROTO_TCP;
2866  f.alproto = ALPROTO_SMTP;
2867 
2868  StreamTcpInitConfig(true);
2869  SMTPTestInitConfig();
2870 
2871  FLOWLOCK_WRLOCK(&f);
2872  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2873  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
2874  if (r != 0) {
2875  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2876  FLOWLOCK_UNLOCK(&f);
2877  goto end;
2878  }
2879  FLOWLOCK_UNLOCK(&f);
2880  SMTPState *smtp_state = f.alstate;
2881  if (smtp_state == NULL) {
2882  printf("no smtp state: ");
2883  goto end;
2884  }
2885  if (smtp_state->input_len != 0 ||
2886  smtp_state->cmds_cnt != 0 ||
2887  smtp_state->cmds_idx != 0 ||
2889  printf("smtp parser in inconsistent state\n");
2890  goto end;
2891  }
2892 
2893  FLOWLOCK_WRLOCK(&f);
2894  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2895  STREAM_TOSERVER, request1, request1_len);
2896  if (r != 0) {
2897  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2898  FLOWLOCK_UNLOCK(&f);
2899  goto end;
2900  }
2901  FLOWLOCK_UNLOCK(&f);
2902  if (smtp_state->input_len != 0 ||
2903  smtp_state->cmds_cnt != 1 ||
2904  smtp_state->cmds_idx != 0 ||
2905  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2907  printf("smtp parser in inconsistent state\n");
2908  goto end;
2909  }
2910 
2911  FLOWLOCK_WRLOCK(&f);
2912  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2913  STREAM_TOCLIENT, reply1, reply1_len);
2914  if (r != 0) {
2915  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2916  FLOWLOCK_UNLOCK(&f);
2917  goto end;
2918  }
2919  FLOWLOCK_UNLOCK(&f);
2920  if (smtp_state->input_len != 0 ||
2921  smtp_state->cmds_cnt != 0 ||
2922  smtp_state->cmds_idx != 0 ||
2925  printf("smtp parser in inconsistent state\n");
2926  goto end;
2927  }
2928 
2929  FLOWLOCK_WRLOCK(&f);
2930  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2931  STREAM_TOSERVER, request2, request2_len);
2932  if (r != 0) {
2933  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2934  FLOWLOCK_UNLOCK(&f);
2935  goto end;
2936  }
2937  FLOWLOCK_UNLOCK(&f);
2938  if (smtp_state->input_len != 0 ||
2939  smtp_state->cmds_cnt != 3 ||
2940  smtp_state->cmds_idx != 0 ||
2941  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2942  smtp_state->cmds[1] != SMTP_COMMAND_OTHER_CMD ||
2943  smtp_state->cmds[2] != SMTP_COMMAND_DATA ||
2947  printf("smtp parser in inconsistent state\n");
2948  goto end;
2949  }
2950 
2951  FLOWLOCK_WRLOCK(&f);
2952  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2953  STREAM_TOCLIENT, reply2, reply2_len);
2954  if (r != 0) {
2955  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2956  FLOWLOCK_UNLOCK(&f);
2957  goto end;
2958  }
2959  FLOWLOCK_UNLOCK(&f);
2960  if (smtp_state->input_len != 0 ||
2961  smtp_state->cmds_cnt != 0 ||
2962  smtp_state->cmds_idx != 0 ||
2966  printf("smtp parser in inconsistent state\n");
2967  goto end;
2968  }
2969 
2970  result = 1;
2971 end:
2972  if (alp_tctx != NULL)
2974  StreamTcpFreeConfig(true);
2975  FLOW_DESTROY(&f);
2976  return result;
2977 }
2978 
2979 /*
2980  * \test Test smtp with just <LF> delimiter instead of <CR><LF>.
2981  */
2982 static int SMTPParserTest04(void)
2983 {
2984  int result = 0;
2985  Flow f;
2986  int r = 0;
2987 
2988  /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
2989  uint8_t welcome_reply[] = {
2990  0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
2991  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2992  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2993  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
2994  0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
2995  0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
2996  };
2997  uint32_t welcome_reply_len = sizeof(welcome_reply);
2998 
2999  /* EHLO boo.com<CR><LF> */
3000  uint8_t request1[] = {
3001  0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
3002  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3003  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3004  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
3005  0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
3006  0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
3007  };
3008  uint32_t request1_len = sizeof(request1);
3009 
3010  TcpSession ssn;
3012 
3013  memset(&f, 0, sizeof(f));
3014  memset(&ssn, 0, sizeof(ssn));
3015 
3016  FLOW_INITIALIZE(&f);
3017  f.protoctx = (void *)&ssn;
3018  f.proto = IPPROTO_TCP;
3019  f.alproto = ALPROTO_SMTP;
3020 
3021  StreamTcpInitConfig(true);
3022  SMTPTestInitConfig();
3023 
3024  FLOWLOCK_WRLOCK(&f);
3025  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3026  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
3027  if (r != 0) {
3028  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3029  FLOWLOCK_UNLOCK(&f);
3030  goto end;
3031  }
3032  FLOWLOCK_UNLOCK(&f);
3033  SMTPState *smtp_state = f.alstate;
3034  if (smtp_state == NULL) {
3035  printf("no smtp state: ");
3036  goto end;
3037  }
3038  if (smtp_state->input_len != 0 ||
3039  smtp_state->cmds_cnt != 0 ||
3040  smtp_state->cmds_idx != 0 ||
3042  printf("smtp parser in inconsistent state\n");
3043  goto end;
3044  }
3045 
3046  FLOWLOCK_WRLOCK(&f);
3047  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3048  STREAM_TOSERVER, request1, request1_len);
3049  if (r != 0) {
3050  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3051  FLOWLOCK_UNLOCK(&f);
3052  goto end;
3053  }
3054  FLOWLOCK_UNLOCK(&f);
3055  if (smtp_state->input_len != 0 ||
3056  smtp_state->cmds_cnt != 1 ||
3057  smtp_state->cmds_idx != 0 ||
3058  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3060  printf("smtp parser in inconsistent state\n");
3061  goto end;
3062  }
3063 
3064  result = 1;
3065 end:
3066  if (alp_tctx != NULL)
3068  StreamTcpFreeConfig(true);
3069  FLOW_DESTROY(&f);
3070  return result;
3071 }
3072 
3073 /*
3074  * \test Test STARTTLS fail.
3075  */
3076 static int SMTPParserTest05(void)
3077 {
3078  int result = 0;
3079  Flow f;
3080  int r = 0;
3081 
3082  /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
3083  uint8_t welcome_reply[] = {
3084  0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
3085  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3086  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3087  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
3088  0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
3089  0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
3090  };
3091  uint32_t welcome_reply_len = sizeof(welcome_reply);
3092 
3093  /* EHLO boo.com<CR><LF> */
3094  uint8_t request1[] = {
3095  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3096  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
3097  };
3098  uint32_t request1_len = sizeof(request1);
3099  /* 250-poona_slack_vm1.localdomain<CR><LF>
3100  * 250-PIPELINING<CR><LF>
3101  * 250-SIZE 10240000<CR><LF>
3102  * 250-VRFY<CR><LF>
3103  * 250-ETRN<CR><LF>
3104  * 250-ENHANCEDSTATUSCODES<CR><LF>
3105  * 250-8BITMIME<CR><LF>
3106  * 250 DSN<CR><LF>
3107  */
3108  uint8_t reply1[] = {
3109  0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
3110  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3111  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3112  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
3113  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
3114  0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
3115  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
3116  0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
3117  0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3118  0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
3119  0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
3120  0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
3121  0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
3122  0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
3123  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
3124  0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
3125  0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
3126  };
3127  uint32_t reply1_len = sizeof(reply1);
3128 
3129  /* STARTTLS<CR><LF> */
3130  uint8_t request2[] = {
3131  0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
3132  0x0d, 0x0a
3133  };
3134  uint32_t request2_len = sizeof(request2);
3135  /* 502 5.5.2 Error: command not recognized<CR><LF> */
3136  uint8_t reply2[] = {
3137  0x35, 0x30, 0x32, 0x20, 0x35, 0x2e, 0x35, 0x2e,
3138  0x32, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x3a,
3139  0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
3140  0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x63,
3141  0x6f, 0x67, 0x6e, 0x69, 0x7a, 0x65, 0x64, 0x0d,
3142  0x0a
3143  };
3144  uint32_t reply2_len = sizeof(reply2);
3145 
3146  /* QUIT<CR><LF> */
3147  uint8_t request3[] = {
3148  0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
3149 
3150  };
3151  uint32_t request3_len = sizeof(request3);
3152  /* 221 2.0.0 Bye<CR><LF> */
3153  uint8_t reply3[] = {
3154  0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
3155  0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
3156  };
3157  uint32_t reply3_len = sizeof(reply3);
3158 
3159  TcpSession ssn;
3161 
3162  memset(&f, 0, sizeof(f));
3163  memset(&ssn, 0, sizeof(ssn));
3164 
3165  FLOW_INITIALIZE(&f);
3166  f.protoctx = (void *)&ssn;
3167  f.proto = IPPROTO_TCP;
3168  f.alproto = ALPROTO_SMTP;
3169 
3170  StreamTcpInitConfig(true);
3171  SMTPTestInitConfig();
3172 
3173  FLOWLOCK_WRLOCK(&f);
3174  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3175  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
3176  if (r != 0) {
3177  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3178  FLOWLOCK_UNLOCK(&f);
3179  goto end;
3180  }
3181  FLOWLOCK_UNLOCK(&f);
3182  SMTPState *smtp_state = f.alstate;
3183  if (smtp_state == NULL) {
3184  printf("no smtp state: ");
3185  goto end;
3186  }
3187  if (smtp_state->input_len != 0 ||
3188  smtp_state->cmds_cnt != 0 ||
3189  smtp_state->cmds_idx != 0 ||
3191  printf("smtp parser in inconsistent state\n");
3192  goto end;
3193  }
3194 
3195  FLOWLOCK_WRLOCK(&f);
3196  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3197  STREAM_TOSERVER, request1, request1_len);
3198  if (r != 0) {
3199  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3200  FLOWLOCK_UNLOCK(&f);
3201  goto end;
3202  }
3203  FLOWLOCK_UNLOCK(&f);
3204  if (smtp_state->input_len != 0 ||
3205  smtp_state->cmds_cnt != 1 ||
3206  smtp_state->cmds_idx != 0 ||
3207  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3209  printf("smtp parser in inconsistent state\n");
3210  goto end;
3211  }
3212 
3213  FLOWLOCK_WRLOCK(&f);
3214  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3215  STREAM_TOCLIENT, reply1, reply1_len);
3216  if (r != 0) {
3217  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3218  FLOWLOCK_UNLOCK(&f);
3219  goto end;
3220  }
3221  FLOWLOCK_UNLOCK(&f);
3222  if (smtp_state->input_len != 0 ||
3223  smtp_state->cmds_cnt != 0 ||
3224  smtp_state->cmds_idx != 0 ||
3227  printf("smtp parser in inconsistent state\n");
3228  goto end;
3229  }
3230 
3231  FLOWLOCK_WRLOCK(&f);
3232  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3233  STREAM_TOSERVER, request2, request2_len);
3234  if (r != 0) {
3235  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3236  FLOWLOCK_UNLOCK(&f);
3237  goto end;
3238  }
3239  FLOWLOCK_UNLOCK(&f);
3240  if (smtp_state->input_len != 0 ||
3241  smtp_state->cmds_cnt != 1 ||
3242  smtp_state->cmds_idx != 0 ||
3243  smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS ||
3246  printf("smtp parser in inconsistent state\n");
3247  goto end;
3248  }
3249 
3250  FLOWLOCK_WRLOCK(&f);
3251  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3252  STREAM_TOCLIENT, reply2, reply2_len);
3253  if (r != 0) {
3254  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3255  FLOWLOCK_UNLOCK(&f);
3256  goto end;
3257  }
3258  FLOWLOCK_UNLOCK(&f);
3259  if (smtp_state->input_len != 0 ||
3260  smtp_state->cmds_cnt != 0 ||
3261  smtp_state->cmds_idx != 0 ||
3264  printf("smtp parser in inconsistent state\n");
3265  goto end;
3266  }
3267 
3268  if ((f.flags & FLOW_NOPAYLOAD_INSPECTION) ||
3270  (((TcpSession *)f.protoctx)->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) ||
3271  (((TcpSession *)f.protoctx)->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
3272  goto end;
3273  }
3274 
3275  FLOWLOCK_WRLOCK(&f);
3276  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3277  STREAM_TOSERVER, request3, request3_len);
3278  if (r != 0) {
3279  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3280  FLOWLOCK_UNLOCK(&f);
3281  goto end;
3282  }
3283  FLOWLOCK_UNLOCK(&f);
3284  if (smtp_state->input_len != 0 ||
3285  smtp_state->cmds_cnt != 1 ||
3286  smtp_state->cmds_idx != 0 ||
3287  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3290  printf("smtp parser in inconsistent state\n");
3291  goto end;
3292  }
3293 
3294  FLOWLOCK_WRLOCK(&f);
3295  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3296  STREAM_TOCLIENT, reply3, reply3_len);
3297  if (r != 0) {
3298  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3299  FLOWLOCK_UNLOCK(&f);
3300  goto end;
3301  }
3302  FLOWLOCK_UNLOCK(&f);
3303  if (smtp_state->input_len != 0 ||
3304  smtp_state->cmds_cnt != 0 ||
3305  smtp_state->cmds_idx != 0 ||
3308  printf("smtp parser in inconsistent state\n");
3309  goto end;
3310  }
3311 
3312  result = 1;
3313 end:
3314  if (alp_tctx != NULL)
3316  StreamTcpFreeConfig(true);
3317  FLOW_DESTROY(&f);
3318  return result;
3319 }
3320 
3321 /**
3322  * \test Test multiple DATA commands(full mail transactions).
3323  */
3324 static int SMTPParserTest06(void)
3325 {
3326  int result = 0;
3327  Flow f;
3328  int r = 0;
3329 
3330  uint8_t welcome_reply[] = {
3331  0x32, 0x32, 0x30, 0x20, 0x62, 0x61, 0x79, 0x30,
3332  0x2d, 0x6d, 0x63, 0x36, 0x2d, 0x66, 0x31, 0x30,
3333  0x2e, 0x62, 0x61, 0x79, 0x30, 0x2e, 0x68, 0x6f,
3334  0x74, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f,
3335  0x6d, 0x20, 0x53, 0x65, 0x6e, 0x64, 0x69, 0x6e,
3336  0x67, 0x20, 0x75, 0x6e, 0x73, 0x6f, 0x6c, 0x69,
3337  0x63, 0x69, 0x74, 0x65, 0x64, 0x20, 0x63, 0x6f,
3338  0x6d, 0x6d, 0x65, 0x72, 0x63, 0x69, 0x61, 0x6c,
3339  0x20, 0x6f, 0x72, 0x20, 0x62, 0x75, 0x6c, 0x6b,
3340  0x20, 0x65, 0x2d, 0x6d, 0x61, 0x69, 0x6c, 0x20,
3341  0x74, 0x6f, 0x20, 0x4d, 0x69, 0x63, 0x72, 0x6f,
3342  0x73, 0x6f, 0x66, 0x74, 0x27, 0x73, 0x20, 0x63,
3343  0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x20,
3344  0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20,
3345  0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x68, 0x69,
3346  0x62, 0x69, 0x74, 0x65, 0x64, 0x2e, 0x20, 0x4f,
3347  0x74, 0x68, 0x65, 0x72, 0x20, 0x72, 0x65, 0x73,
3348  0x74, 0x72, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e,
3349  0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x66, 0x6f,
3350  0x75, 0x6e, 0x64, 0x20, 0x61, 0x74, 0x20, 0x68,
3351  0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x72,
3352  0x69, 0x76, 0x61, 0x63, 0x79, 0x2e, 0x6d, 0x73,
3353  0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x41, 0x6e,
3354  0x74, 0x69, 0x2d, 0x73, 0x70, 0x61, 0x6d, 0x2f,
3355  0x2e, 0x20, 0x56, 0x69, 0x6f, 0x6c, 0x61, 0x74,
3356  0x69, 0x6f, 0x6e, 0x73, 0x20, 0x77, 0x69, 0x6c,
3357  0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74,
3358  0x20, 0x69, 0x6e, 0x20, 0x75, 0x73, 0x65, 0x20,
3359  0x6f, 0x66, 0x20, 0x65, 0x71, 0x75, 0x69, 0x70,
3360  0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x63,
3361  0x61, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20,
3362  0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e,
3363  0x69, 0x61, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6f,
3364  0x74, 0x68, 0x65, 0x72, 0x20, 0x73, 0x74, 0x61,
3365  0x74, 0x65, 0x73, 0x2e, 0x20, 0x46, 0x72, 0x69,
3366  0x2c, 0x20, 0x31, 0x36, 0x20, 0x46, 0x65, 0x62,
3367  0x20, 0x32, 0x30, 0x30, 0x37, 0x20, 0x30, 0x35,
3368  0x3a, 0x30, 0x33, 0x3a, 0x32, 0x33, 0x20, 0x2d,
3369  0x30, 0x38, 0x30, 0x30, 0x20, 0x0d, 0x0a
3370  };
3371  uint32_t welcome_reply_len = sizeof(welcome_reply);
3372 
3373  uint8_t request1[] = {
3374  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x45, 0x58, 0x43,
3375  0x48, 0x41, 0x4e, 0x47, 0x45, 0x32, 0x2e, 0x63,
3376  0x67, 0x63, 0x65, 0x6e, 0x74, 0x2e, 0x6d, 0x69,
3377  0x61, 0x6d, 0x69, 0x2e, 0x65, 0x64, 0x75, 0x0d,
3378  0x0a
3379  };
3380  uint32_t request1_len = sizeof(request1);
3381 
3382  uint8_t reply1[] = {
3383  0x32, 0x35, 0x30, 0x2d, 0x62, 0x61, 0x79, 0x30,
3384  0x2d, 0x6d, 0x63, 0x36, 0x2d, 0x66, 0x31, 0x30,
3385  0x2e, 0x62, 0x61, 0x79, 0x30, 0x2e, 0x68, 0x6f,
3386  0x74, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f,
3387  0x6d, 0x20, 0x28, 0x33, 0x2e, 0x33, 0x2e, 0x31,
3388  0x2e, 0x34, 0x29, 0x20, 0x48, 0x65, 0x6c, 0x6c,
3389  0x6f, 0x20, 0x5b, 0x31, 0x32, 0x39, 0x2e, 0x31,
3390  0x37, 0x31, 0x2e, 0x33, 0x32, 0x2e, 0x35, 0x39,
3391  0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53,
3392  0x49, 0x5a, 0x45, 0x20, 0x32, 0x39, 0x36, 0x39,
3393  0x36, 0x30, 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35,
3394  0x30, 0x2d, 0x38, 0x62, 0x69, 0x74, 0x6d, 0x69,
3395  0x6d, 0x65, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3396  0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x4d, 0x49,
3397  0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3398  0x43, 0x48, 0x55, 0x4e, 0x4b, 0x49, 0x4e, 0x47,
3399  0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x41, 0x55,
3400  0x54, 0x48, 0x20, 0x4c, 0x4f, 0x47, 0x49, 0x4e,
3401  0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x41, 0x55,
3402  0x54, 0x48, 0x3d, 0x4c, 0x4f, 0x47, 0x49, 0x4e,
3403  0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20, 0x4f, 0x4b,
3404  0x0d, 0x0a
3405  };
3406  uint32_t reply1_len = sizeof(reply1);
3407 
3408  /* MAIL FROM:asdff@asdf.com<CR><LF> */
3409  uint8_t request2[] = {
3410  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
3411  0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
3412  0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
3413  0x0d, 0x0a
3414  };
3415  uint32_t request2_len = sizeof(request2);
3416  /* 250 2.1.0 Ok<CR><LF> */
3417  uint8_t reply2[] = {
3418  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
3419  0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
3420  };
3421  uint32_t reply2_len = sizeof(reply2);
3422 
3423  /* RCPT TO:bimbs@gmail.com<CR><LF> */
3424  uint8_t request3[] = {
3425  0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
3426  0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
3427  0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
3428  0x0a
3429  };
3430  uint32_t request3_len = sizeof(request3);
3431  /* 250 2.1.5 Ok<CR><LF> */
3432  uint8_t reply3[] = {
3433  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
3434  0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
3435  };
3436  uint32_t reply3_len = sizeof(reply3);
3437 
3438  /* BDAT 51<CR><LF> */
3439  uint8_t request4[] = {
3440  0x42, 0x44, 0x41, 0x54, 0x20, 0x35, 0x31, 0x0d,
3441  0x0a,
3442  };
3443  uint32_t request4_len = sizeof(request4);
3444 
3445  uint8_t request5[] = {
3446  0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
3447  0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
3448  0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
3449  0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x0d, 0x0a,
3450  };
3451  uint32_t request5_len = sizeof(request5);
3452 
3453  uint8_t request6[] = {
3454  0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
3455  0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
3456  0x66, 0x0d, 0x0a,
3457  };
3458  uint32_t request6_len = sizeof(request6);
3459 
3460  TcpSession ssn;
3462 
3463  memset(&f, 0, sizeof(f));
3464  memset(&ssn, 0, sizeof(ssn));
3465 
3466  FLOW_INITIALIZE(&f);
3467  f.protoctx = (void *)&ssn;
3468  f.proto = IPPROTO_TCP;
3469  f.alproto = ALPROTO_SMTP;
3470 
3471  StreamTcpInitConfig(true);
3472  SMTPTestInitConfig();
3473 
3474  FLOWLOCK_WRLOCK(&f);
3475  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3476  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
3477  if (r != 0) {
3478  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3479  FLOWLOCK_UNLOCK(&f);
3480  goto end;
3481  }
3482  FLOWLOCK_UNLOCK(&f);
3483  SMTPState *smtp_state = f.alstate;
3484  if (smtp_state == NULL) {
3485  printf("no smtp state: ");
3486  goto end;
3487  }
3488  if (smtp_state->input_len != 0 ||
3489  smtp_state->cmds_cnt != 0 ||
3490  smtp_state->cmds_idx != 0 ||
3492  printf("smtp parser in inconsistent state\n");
3493  goto end;
3494  }
3495 
3496  FLOWLOCK_WRLOCK(&f);
3497  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3498  STREAM_TOSERVER, request1, request1_len);
3499  if (r != 0) {
3500  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3501  FLOWLOCK_UNLOCK(&f);
3502  goto end;
3503  }
3504  FLOWLOCK_UNLOCK(&f);
3505  if (smtp_state->input_len != 0 ||
3506  smtp_state->cmds_cnt != 1 ||
3507  smtp_state->cmds_idx != 0 ||
3508  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3510  printf("smtp parser in inconsistent state\n");
3511  goto end;
3512  }
3513 
3514  FLOWLOCK_WRLOCK(&f);
3515  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3516  STREAM_TOCLIENT, reply1, reply1_len);
3517  if (r != 0) {
3518  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3519  FLOWLOCK_UNLOCK(&f);
3520  goto end;
3521  }
3522  FLOWLOCK_UNLOCK(&f);
3523  if (smtp_state->input_len != 0 ||
3524  smtp_state->cmds_cnt != 0 ||
3525  smtp_state->cmds_idx != 0 ||
3527  printf("smtp parser in inconsistent state\n");
3528  goto end;
3529  }
3530 
3531  FLOWLOCK_WRLOCK(&f);
3532  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3533  STREAM_TOSERVER, request2, request2_len);
3534  if (r != 0) {
3535  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3536  FLOWLOCK_UNLOCK(&f);
3537  goto end;
3538  }
3539  FLOWLOCK_UNLOCK(&f);
3540  if (smtp_state->input_len != 0 ||
3541  smtp_state->cmds_cnt != 1 ||
3542  smtp_state->cmds_idx != 0 ||
3543  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3545  printf("smtp parser in inconsistent state\n");
3546  goto end;
3547  }
3548 
3549  FLOWLOCK_WRLOCK(&f);
3550  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3551  STREAM_TOCLIENT, reply2, reply2_len);
3552  if (r != 0) {
3553  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3554  FLOWLOCK_UNLOCK(&f);
3555  goto end;
3556  }
3557  FLOWLOCK_UNLOCK(&f);
3558  if (smtp_state->input_len != 0 ||
3559  smtp_state->cmds_cnt != 0 ||
3560  smtp_state->cmds_idx != 0 ||
3562  printf("smtp parser in inconsistent state\n");
3563  goto end;
3564  }
3565 
3566  FLOWLOCK_WRLOCK(&f);
3567  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3568  STREAM_TOSERVER, request3, request3_len);
3569  if (r != 0) {
3570  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3571  FLOWLOCK_UNLOCK(&f);
3572  goto end;
3573  }
3574  FLOWLOCK_UNLOCK(&f);
3575  if (smtp_state->input_len != 0 ||
3576  smtp_state->cmds_cnt != 1 ||
3577  smtp_state->cmds_idx != 0 ||
3578  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3580  printf("smtp parser in inconsistent state\n");
3581  goto end;
3582  }
3583 
3584  FLOWLOCK_WRLOCK(&f);
3585  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3586  STREAM_TOCLIENT, reply3, reply3_len);
3587  if (r != 0) {
3588  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3589  FLOWLOCK_UNLOCK(&f);
3590  goto end;
3591  }
3592  FLOWLOCK_UNLOCK(&f);
3593  if (smtp_state->input_len != 0 ||
3594  smtp_state->cmds_cnt != 0 ||
3595  smtp_state->cmds_idx != 0 ||
3597  printf("smtp parser in inconsistent state\n");
3598  goto end;
3599  }
3600 
3601  FLOWLOCK_WRLOCK(&f);
3602  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3603  STREAM_TOSERVER, request4, request4_len);
3604  if (r != 0) {
3605  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3606  FLOWLOCK_UNLOCK(&f);
3607  goto end;
3608  }
3609  FLOWLOCK_UNLOCK(&f);
3610  if (smtp_state->input_len != 0 ||
3611  smtp_state->cmds_cnt != 1 ||
3612  smtp_state->cmds_idx != 0 ||
3613  smtp_state->cmds[0] != SMTP_COMMAND_BDAT ||
3616  smtp_state->bdat_chunk_len != 51 ||
3617  smtp_state->bdat_chunk_idx != 0) {
3618  printf("smtp parser in inconsistent state\n");
3619  goto end;
3620  }
3621 
3622  FLOWLOCK_WRLOCK(&f);
3623  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3624  STREAM_TOSERVER, request5, request5_len);
3625  if (r != 0) {
3626  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3627  FLOWLOCK_UNLOCK(&f);
3628  goto end;
3629  }
3630  FLOWLOCK_UNLOCK(&f);
3631  if (smtp_state->input_len != 0 ||
3632  smtp_state->cmds_cnt != 1 ||
3633  smtp_state->cmds_idx != 0 ||
3636  smtp_state->bdat_chunk_len != 51 ||
3637  smtp_state->bdat_chunk_idx != 32) {
3638  printf("smtp parser in inconsistent state\n");
3639  goto end;
3640  }
3641 
3642  FLOWLOCK_WRLOCK(&f);
3643  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3644  STREAM_TOSERVER, request6, request6_len);
3645  if (r != 0) {
3646  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3647  FLOWLOCK_UNLOCK(&f);
3648  goto end;
3649  }
3650  FLOWLOCK_UNLOCK(&f);
3651  if (smtp_state->input_len != 0 ||
3652  smtp_state->cmds_cnt != 1 ||
3653  smtp_state->cmds_idx != 0 ||
3655  smtp_state->bdat_chunk_len != 51 ||
3656  smtp_state->bdat_chunk_idx != 51) {
3657  printf("smtp parser in inconsistent state\n");
3658  goto end;
3659  }
3660 
3661  result = 1;
3662 end:
3663  if (alp_tctx != NULL)
3665  StreamTcpFreeConfig(true);
3666  FLOW_DESTROY(&f);
3667  return result;
3668 }
3669 
3670 static int SMTPParserTest12(void)
3671 {
3672  int result = 0;
3673  Signature *s = NULL;
3674  ThreadVars th_v;
3675  Packet *p = NULL;
3676  Flow f;
3677  TcpSession ssn;
3678  DetectEngineThreadCtx *det_ctx = NULL;
3679  DetectEngineCtx *de_ctx = NULL;
3680  SMTPState *smtp_state = NULL;
3681  int r = 0;
3682 
3683  /* EHLO boo.com<CR><LF> */
3684  uint8_t request1[] = {
3685  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3686  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3687  };
3688  int32_t request1_len = sizeof(request1);
3689 
3690  /* 388<CR><LF>
3691  */
3692  uint8_t reply1[] = {
3693  0x31, 0x38, 0x38, 0x0d, 0x0a,
3694  };
3695  uint32_t reply1_len = sizeof(reply1);
3696 
3698 
3699  memset(&th_v, 0, sizeof(th_v));
3700  memset(&f, 0, sizeof(f));
3701  memset(&ssn, 0, sizeof(ssn));
3702 
3703  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
3704 
3705  FLOW_INITIALIZE(&f);
3706  f.protoctx = (void *)&ssn;
3707  f.proto = IPPROTO_TCP;
3708  f.alproto = ALPROTO_SMTP;
3709  p->flow = &f;
3713  f.alproto = ALPROTO_SMTP;
3714 
3715  StreamTcpInitConfig(true);
3716  SMTPTestInitConfig();
3717 
3719  if (de_ctx == NULL)
3720  goto end;
3721 
3722  de_ctx->flags |= DE_QUIET;
3723 
3724  s = DetectEngineAppendSig(de_ctx,"alert tcp any any -> any any "
3725  "(msg:\"SMTP event handling\"; "
3726  "app-layer-event: smtp.invalid_reply; "
3727  "sid:1;)");
3728  if (s == NULL)
3729  goto end;
3730 
3732  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
3733 
3734  FLOWLOCK_WRLOCK(&f);
3735  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3736  STREAM_TOSERVER | STREAM_START, request1,
3737  request1_len);
3738  if (r != 0) {
3739  printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
3740  FLOWLOCK_UNLOCK(&f);
3741  goto end;
3742  }
3743  FLOWLOCK_UNLOCK(&f);
3744 
3745  smtp_state = f.alstate;
3746  if (smtp_state == NULL) {
3747  printf("no smtp state: ");
3748  goto end;
3749  }
3750 
3751  /* do detect */
3752  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3753 
3754  if (PacketAlertCheck(p, 1)) {
3755  printf("sid 1 matched. It shouldn't match: ");
3756  goto end;
3757  }
3758 
3759  FLOWLOCK_WRLOCK(&f);
3760  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3761  STREAM_TOCLIENT | STREAM_TOCLIENT, reply1,
3762  reply1_len);
3763  if (r == 0) {
3764  printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
3765  FLOWLOCK_UNLOCK(&f);
3766  goto end;
3767  }
3768  FLOWLOCK_UNLOCK(&f);
3769 
3770  /* do detect */
3771  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3772 
3773  if (!PacketAlertCheck(p, 1)) {
3774  printf("sid 1 didn't match. Should have matched: ");
3775  goto end;
3776  }
3777 
3778  result = 1;
3779 
3780 end:
3783 
3784  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
3786 
3787  if (alp_tctx != NULL)
3789  StreamTcpFreeConfig(true);
3790  FLOW_DESTROY(&f);
3791  UTHFreePackets(&p, 1);
3792  return result;
3793 }
3794 
3795 static int SMTPParserTest13(void)
3796 {
3797  int result = 0;
3798  Signature *s = NULL;
3799  ThreadVars th_v;
3800  Packet *p = NULL;
3801  Flow f;
3802  TcpSession ssn;
3803  DetectEngineThreadCtx *det_ctx = NULL;
3804  DetectEngineCtx *de_ctx = NULL;
3805  SMTPState *smtp_state = NULL;
3806  int r = 0;
3807 
3808  /* EHLO boo.com<CR><LF> */
3809  uint8_t request1[] = {
3810  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3811  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3812  };
3813  int32_t request1_len = sizeof(request1);
3814 
3815  /* 250<CR><LF>
3816  */
3817  uint8_t reply1[] = {
3818  0x32, 0x35, 0x30, 0x0d, 0x0a,
3819  };
3820  uint32_t reply1_len = sizeof(reply1);
3821 
3822  /* MAIL FROM:pbsf@asdfs.com<CR><LF>
3823  * RCPT TO:pbsf@asdfs.com<CR><LF>
3824  * DATA<CR><LF>
3825  * STARTTLS<CR><LF>
3826  */
3827  uint8_t request2[] = {
3828  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
3829  0x4d, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
3830  0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
3831  0x0d, 0x0a, 0x52, 0x43, 0x50, 0x54, 0x20, 0x54,
3832  0x4f, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
3833  0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
3834  0x0d, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a,
3835  0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
3836  0x0d, 0x0a
3837  };
3838  uint32_t request2_len = sizeof(request2);
3839 
3841 
3842  memset(&th_v, 0, sizeof(th_v));
3843  memset(&f, 0, sizeof(f));
3844  memset(&ssn, 0, sizeof(ssn));
3845 
3846  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
3847 
3848  FLOW_INITIALIZE(&f);
3849  f.protoctx = (void *)&ssn;
3850  f.proto = IPPROTO_TCP;
3851  f.alproto = ALPROTO_SMTP;
3852  p->flow = &f;
3856  f.alproto = ALPROTO_SMTP;
3857 
3858  StreamTcpInitConfig(true);
3859  SMTPTestInitConfig();
3860 
3862  if (de_ctx == NULL)
3863  goto end;
3864 
3865  de_ctx->flags |= DE_QUIET;
3866 
3867  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
3868  "(msg:\"SMTP event handling\"; "
3869  "app-layer-event: "
3870  "smtp.invalid_pipelined_sequence; "
3871  "sid:1;)");
3872  if (s == NULL)
3873  goto end;
3874 
3876  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
3877 
3878  FLOWLOCK_WRLOCK(&f);
3879  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3880  STREAM_TOSERVER | STREAM_START, request1,
3881  request1_len);
3882  if (r != 0) {
3883  printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
3884  FLOWLOCK_UNLOCK(&f);
3885  goto end;
3886  }
3887  FLOWLOCK_UNLOCK(&f);
3888 
3889  smtp_state = f.alstate;
3890  if (smtp_state == NULL) {
3891  printf("no smtp state: ");
3892  goto end;
3893  }
3894 
3895  /* do detect */
3896  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3897 
3898  if (PacketAlertCheck(p, 1)) {
3899  printf("sid 1 matched. It shouldn't match: ");
3900  goto end;
3901  }
3902 
3903  FLOWLOCK_WRLOCK(&f);
3904  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3905  STREAM_TOCLIENT, reply1, reply1_len);
3906  if (r != 0) {
3907  printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
3908  FLOWLOCK_UNLOCK(&f);
3909  goto end;
3910  }
3911  FLOWLOCK_UNLOCK(&f);
3912 
3913  /* do detect */
3914  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3915 
3916  if (PacketAlertCheck(p, 1)) {
3917  printf("sid 1 matched. It shouldn't match: ");
3918  goto end;
3919  }
3920 
3921  FLOWLOCK_WRLOCK(&f);
3922  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3923  STREAM_TOSERVER, request2, request2_len);
3924  if (r != 0) {
3925  printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
3926  FLOWLOCK_UNLOCK(&f);
3927  goto end;
3928  }
3929  FLOWLOCK_UNLOCK(&f);
3930 
3931  /* do detect */
3932  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3933 
3934  if (!PacketAlertCheck(p, 1)) {
3935  printf("sid 1 didn't match. Should have matched: ");
3936  goto end;
3937  }
3938 
3939  result = 1;
3940 
3941 end:
3944 
3945  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
3947 
3948  if (alp_tctx != NULL)
3950  StreamTcpFreeConfig(true);
3951  FLOW_DESTROY(&f);
3952  UTHFreePackets(&p, 1);
3953  return result;
3954 }
3955 
3956 /**
3957  * \test Test DATA command w/MIME message.
3958  */
3959 static int SMTPParserTest14(void)
3960 {
3961  int result = 0;
3962  Flow f;
3963  int r = 0;
3964 
3965  /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
3966  static uint8_t welcome_reply[] = {
3967  0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
3968  0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
3969  0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
3970  0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
3971  0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
3972  0x0d, 0x0a
3973  };
3974  static uint32_t welcome_reply_len = sizeof(welcome_reply);
3975 
3976  /* EHLO boo.com<CR><LF> */
3977  static uint8_t request1[] = {
3978  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3979  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
3980  };
3981  static uint32_t request1_len = sizeof(request1);
3982  /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
3983  * 250-SIZE 35882577<CR><LF>
3984  * 250-8BITMIME<CR><LF>
3985  * 250-STARTTLS<CR><LF>
3986  * 250 ENHANCEDSTATUSCODES<CR><LF>
3987  */
3988  static uint8_t reply1[] = {
3989  0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
3990  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3991  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3992  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
3993  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
3994  0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
3995  0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3996  0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
3997  0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
3998  0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
3999  0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
4000  0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
4001  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
4002  0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
4003  0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
4004  };
4005  static uint32_t reply1_len = sizeof(reply1);
4006 
4007  /* MAIL FROM:asdff@asdf.com<CR><LF> */
4008  static uint8_t request2[] = {
4009  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
4010  0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
4011  0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
4012  0x0d, 0x0a
4013  };
4014  static uint32_t request2_len = sizeof(request2);
4015  /* 250 2.1.0 Ok<CR><LF> */
4016  static uint8_t reply2[] = {
4017  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
4018  0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
4019  };
4020  static uint32_t reply2_len = sizeof(reply2);
4021 
4022  /* RCPT TO:bimbs@gmail.com<CR><LF> */
4023  static uint8_t request3[] = {
4024  0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
4025  0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
4026  0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
4027  0x0a
4028  };
4029  static uint32_t request3_len = sizeof(request3);
4030  /* 250 2.1.5 Ok<CR><LF> */
4031  static uint8_t reply3[] = {
4032  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
4033  0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
4034  };
4035  static uint32_t reply3_len = sizeof(reply3);
4036 
4037  /* DATA<CR><LF> */
4038  static uint8_t request4[] = {
4039  0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
4040  };
4041  static uint32_t request4_len = sizeof(request4);
4042  /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
4043  static uint8_t reply4[] = {
4044  0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
4045  0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
4046  0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
4047  0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
4048  0x4c, 0x46, 0x3e, 0x0d, 0x0a
4049  };
4050  static uint32_t reply4_len = sizeof(reply4);
4051 
4052  /* MIME_MSG */
4053  static uint64_t filesize = 133;
4054  static uint8_t request4_msg[] = {
4055  0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72,
4056  0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E,
4057  0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
4058  0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A,
4059  0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61,
4060  0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74,
4061  0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61,
4062  0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
4063  0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73,
4064  0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F,
4065  0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61,
4066  0x73, 0x65, 0x36, 0x34, 0x0D, 0x0A, 0x43, 0x6F,
4067  0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x44, 0x69,
4068  0x73, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F,
4069  0x6E, 0x3A, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63,
4070  0x68, 0x6D, 0x65, 0x6E, 0x74, 0x3B, 0x20, 0x66,
4071  0x69, 0x6C, 0x65, 0x6E, 0x61, 0x6D, 0x65, 0x3D,
4072  0x22, 0x74, 0x65, 0x73, 0x74, 0x2E, 0x65, 0x78,
4073  0x65, 0x22, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x54,
4074  0x56, 0x6F, 0x41, 0x41, 0x46, 0x42, 0x46, 0x41,
4075  0x41, 0x42, 0x4D, 0x41, 0x51, 0x45, 0x41, 0x61,
4076  0x69, 0x70, 0x59, 0x77, 0x77, 0x41, 0x41, 0x41,
4077  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
4078  0x41, 0x41, 0x44, 0x41, 0x51, 0x73, 0x42, 0x43,
4079  0x41, 0x41, 0x42, 0x41, 0x41, 0x43, 0x41, 0x41,
4080  0x41, 0x41, 0x41, 0x41, 0x48, 0x6B, 0x41, 0x41,
4081  0x41, 0x41, 0x4D, 0x41, 0x41, 0x41, 0x41, 0x65,
4082  0x51, 0x41, 0x41, 0x41, 0x41, 0x77, 0x41, 0x41,
4083  0x41, 0x41, 0x41, 0x41, 0x45, 0x41, 0x41, 0x42,
4084  0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
4085  0x41, 0x42, 0x30, 0x41, 0x41, 0x41, 0x41, 0x49,
4086  0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
4087  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
4088  0x41, 0x45, 0x41, 0x41, 0x49, 0x67, 0x41, 0x41,
4089  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4090  0x67, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4091  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4092  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4093  0x41, 0x42, 0x63, 0x58, 0x44, 0x59, 0x32, 0x4C,
4094  0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C,
4095  0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F,
4096  0x41, 0x3D, 0x3D, 0x0D,0x0A };
4097  static uint32_t request4_msg_len = sizeof(request4_msg);
4098 
4099  /* DATA COMPLETED */
4100  static uint8_t request4_end[] = {
4101  0x0d, 0x0a, 0x2e, 0x0d, 0x0a
4102  };
4103  static uint32_t request4_end_len = sizeof(request4_end);
4104  /* 250 2.0.0 Ok: queued as 6A1AF20BF2<CR><LF> */
4105  static uint8_t reply4_end[] = {
4106  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
4107  0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
4108  0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
4109  0x36, 0x41, 0x31, 0x41, 0x46, 0x32, 0x30, 0x42,
4110  0x46, 0x32, 0x0d, 0x0a
4111  };
4112  static uint32_t reply4_end_len = sizeof(reply4_end);
4113 
4114  /* QUIT<CR><LF> */
4115  static uint8_t request5[] = {
4116  0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
4117  };
4118  static uint32_t request5_len = sizeof(request5);
4119  /* 221 2.0.0 Bye<CR><LF> */
4120  static uint8_t reply5[] = {
4121  0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
4122  0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
4123  };
4124  static uint32_t reply5_len = sizeof(reply5);
4125 
4126  TcpSession ssn;
4128 
4129  memset(&f, 0, sizeof(f));
4130  memset(&ssn, 0, sizeof(ssn));
4131 
4132  FLOW_INITIALIZE(&f);
4133  f.protoctx = (void *)&ssn;
4134  f.proto = IPPROTO_TCP;
4135  f.alproto = ALPROTO_SMTP;
4136 
4137  StreamTcpInitConfig(true);
4138  SMTPTestInitConfig();
4139 
4140  FLOWLOCK_WRLOCK(&f);
4141  /* Welcome reply */
4142  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4143  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
4144  if (r != 0) {
4145  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4146  FLOWLOCK_UNLOCK(&f);
4147  goto end;
4148  }
4149  FLOWLOCK_UNLOCK(&f);
4150  SMTPState *smtp_state = f.alstate;
4151  if (smtp_state == NULL) {
4152  printf("no smtp state: ");
4153  goto end;
4154  }
4155  if (smtp_state->input_len != 0 ||
4156  smtp_state->cmds_cnt != 0 ||
4157  smtp_state->cmds_idx != 0 ||
4159  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4160  goto end;
4161  }
4162 
4163  FLOWLOCK_WRLOCK(&f);
4164  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4165  STREAM_TOSERVER, request1, request1_len);
4166  if (r != 0) {
4167  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4168  FLOWLOCK_UNLOCK(&f);
4169  goto end;
4170  }
4171  FLOWLOCK_UNLOCK(&f);
4172  if (smtp_state->input_len != 0 ||
4173  smtp_state->cmds_cnt != 1 ||
4174  smtp_state->cmds_idx != 0 ||
4175  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4177  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4178  goto end;
4179  }
4180 
4181  FLOWLOCK_WRLOCK(&f);
4182  /* EHLO Reply */
4183  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4184  STREAM_TOCLIENT, reply1, reply1_len);
4185  if (r != 0) {
4186  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4187  FLOWLOCK_UNLOCK(&f);
4188  goto end;
4189  }
4190 
4191  if ((smtp_state->helo_len != 7) || strncmp("boo.com", (char *)smtp_state->helo, 7)) {
4192  printf("incorrect parsing of HELO field '%s' (%d)\n", smtp_state->helo, smtp_state->helo_len);
4193  FLOWLOCK_UNLOCK(&f);
4194  goto end;
4195  }
4196 
4197  FLOWLOCK_UNLOCK(&f);
4198  if (smtp_state->input_len != 0 ||
4199  smtp_state->cmds_cnt != 0 ||
4200  smtp_state->cmds_idx != 0 ||
4202  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4203  goto end;
4204  }
4205 
4206  FLOWLOCK_WRLOCK(&f);
4207  /* MAIL FROM Request */
4208  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4209  STREAM_TOSERVER, request2, request2_len);
4210  if (r != 0) {
4211  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4212  FLOWLOCK_UNLOCK(&f);
4213  goto end;
4214  }
4215  FLOWLOCK_UNLOCK(&f);
4216  if (smtp_state->input_len != 0 ||
4217  smtp_state->cmds_cnt != 1 ||
4218  smtp_state->cmds_idx != 0 ||
4219  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4221  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4222  goto end;
4223  }
4224 
4225  FLOWLOCK_WRLOCK(&f);
4226  /* MAIL FROM Reply */
4227  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4228  STREAM_TOCLIENT, reply2, reply2_len);
4229  if (r != 0) {
4230  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4231  FLOWLOCK_UNLOCK(&f);
4232  goto end;
4233  }
4234 
4235  if ((smtp_state->curr_tx->mail_from_len != 14) ||
4236  strncmp("asdff@asdf.com", (char *)smtp_state->curr_tx->mail_from, 14)) {
4237  printf("incorrect parsing of MAIL FROM field '%s' (%d)\n",
4238  smtp_state->curr_tx->mail_from,
4239  smtp_state->curr_tx->mail_from_len);
4240  FLOWLOCK_UNLOCK(&f);
4241  goto end;
4242  }
4243 
4244  FLOWLOCK_UNLOCK(&f);
4245  if (smtp_state->input_len != 0 ||
4246  smtp_state->cmds_cnt != 0 ||
4247  smtp_state->cmds_idx != 0 ||
4249  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4250  goto end;
4251  }
4252 
4253  FLOWLOCK_WRLOCK(&f);
4254  /* RCPT TO Request */
4255  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4256  STREAM_TOSERVER, request3, request3_len);
4257  if (r != 0) {
4258  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4259  FLOWLOCK_UNLOCK(&f);
4260  goto end;
4261  }
4262  FLOWLOCK_UNLOCK(&f);
4263  if (smtp_state->input_len != 0 ||
4264  smtp_state->cmds_cnt != 1 ||
4265  smtp_state->cmds_idx != 0 ||
4266  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4268  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4269  goto end;
4270  }
4271 
4272  FLOWLOCK_WRLOCK(&f);
4273  /* RCPT TO Reply */
4274  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4275  STREAM_TOCLIENT, reply3, reply3_len);
4276  if (r != 0) {
4277  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4278  FLOWLOCK_UNLOCK(&f);
4279  goto end;
4280  }
4281  FLOWLOCK_UNLOCK(&f);
4282  if (smtp_state->input_len != 0 ||
4283  smtp_state->cmds_cnt != 0 ||
4284  smtp_state->cmds_idx != 0 ||
4286  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4287  goto end;
4288  }
4289 
4290  /* Enable mime decoding */
4291  smtp_config.decode_mime = true;
4295 
4296  FLOWLOCK_WRLOCK(&f);
4297  /* DATA request */
4298  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4299  STREAM_TOSERVER, request4, request4_len);
4300  if (r != 0) {
4301  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4302  FLOWLOCK_UNLOCK(&f);
4303  goto end;
4304  }
4305  FLOWLOCK_UNLOCK(&f);
4306 
4307  if (smtp_state->input_len != 0 ||
4308  smtp_state->cmds_cnt != 1 ||
4309  smtp_state->cmds_idx != 0 ||
4310  smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
4312  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4313  goto end;
4314  }
4315 
4316  FLOWLOCK_WRLOCK(&f);
4317  /* Data reply */
4318  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4319  STREAM_TOCLIENT, reply4, reply4_len);
4320  if (r != 0) {
4321  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4322  FLOWLOCK_UNLOCK(&f);
4323  goto end;
4324  }
4325  FLOWLOCK_UNLOCK(&f);
4326  if (smtp_state->input_len != 0 ||
4327  smtp_state->cmds_cnt != 0 ||
4328  smtp_state->cmds_idx != 0 ||
4331  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4332  goto end;
4333  }
4334 
4335  FLOWLOCK_WRLOCK(&f);
4336  /* DATA message */
4337  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4338  STREAM_TOSERVER, request4_msg, request4_msg_len);
4339  if (r != 0) {
4340  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4341  FLOWLOCK_UNLOCK(&f);
4342  goto end;
4343  }
4344  FLOWLOCK_UNLOCK(&f);
4345 
4346  if (smtp_state->input_len != 0 ||
4347  smtp_state->cmds_cnt != 0 ||
4348  smtp_state->cmds_idx != 0 ||
4349  smtp_state->curr_tx->mime_state == NULL || smtp_state->curr_tx->msg_head == NULL || /* MIME data structures */
4352  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4353  goto end;
4354  }
4355 
4356  FLOWLOCK_WRLOCK(&f);
4357  /* DATA . request */
4358  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4359  STREAM_TOSERVER, request4_end, request4_end_len);
4360  if (r != 0) {
4361  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4362  FLOWLOCK_UNLOCK(&f);
4363  goto end;
4364  }
4365  FLOWLOCK_UNLOCK(&f);
4366 
4367  if (smtp_state->input_len != 0 ||
4368  smtp_state->cmds_cnt != 1 ||
4369  smtp_state->cmds_idx != 0 ||
4370  smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
4371  smtp_state->curr_tx->mime_state == NULL || smtp_state->curr_tx->msg_head == NULL || /* MIME data structures */
4373  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4374  goto end;
4375  }
4376 
4377  SMTPState *state = (SMTPState *) f.alstate;
4378  FileContainer *files = state->files_ts;
4379  if (files != NULL && files->head != NULL) {
4380  File *file = files->head;
4381 
4382  if(strncmp((const char *)file->name, "test.exe", 8) != 0){
4383  printf("smtp-mime file name is incorrect");
4384  goto end;
4385  }
4386  if (FileTrackedSize(file) != filesize){
4387  printf("smtp-mime file size %"PRIu64" is incorrect", FileDataSize(file));
4388  goto end;
4389  }
4390  static uint8_t org_binary[] = {
4391  0x4D, 0x5A, 0x00, 0x00, 0x50, 0x45, 0x00, 0x00,
4392  0x4C, 0x01, 0x01, 0x00, 0x6A, 0x2A, 0x58, 0xC3,
4393  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4394  0x04, 0x00, 0x03, 0x01, 0x0B, 0x01, 0x08, 0x00,
4395  0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
4396  0x79, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
4397  0x79, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
4398  0x00, 0x00, 0x40, 0x00, 0x04, 0x00, 0x00, 0x00,
4399  0x04, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00,
4400  0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
4401  0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00,
4402  0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4403  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4404  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4405  0x00, 0x00, 0x00, 0x00, 0x5C, 0x5C, 0x36, 0x36,
4406  0x2E, 0x39, 0x33, 0x2E, 0x36, 0x38, 0x2E, 0x36,
4407  0x5C, 0x7A, 0x00, 0x00, 0x38,};
4408 
4410  org_binary, sizeof(org_binary)) != 1)
4411  {
4412  printf("smtp-mime file data incorrect\n");
4413  goto end;
4414  }
4415  }
4416 
4417  FLOWLOCK_WRLOCK(&f);
4418  /* DATA . reply */
4419  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4420  STREAM_TOCLIENT, reply4_end, reply4_end_len);
4421  if (r != 0) {
4422  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4423  FLOWLOCK_UNLOCK(&f);
4424  goto end;
4425  }
4426  FLOWLOCK_UNLOCK(&f);
4427  if (smtp_state->input_len != 0 ||
4428  smtp_state->cmds_cnt != 0 ||
4429  smtp_state->cmds_idx != 0 ||
4431  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4432  goto end;
4433  }
4434 
4435  FLOWLOCK_WRLOCK(&f);
4436  /* QUIT Request */
4437  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4438  STREAM_TOSERVER, request5, request5_len);
4439  if (r != 0) {
4440  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4441  FLOWLOCK_UNLOCK(&f);
4442  goto end;
4443  }
4444  FLOWLOCK_UNLOCK(&f);
4445  if (smtp_state->input_len != 0 ||
4446  smtp_state->cmds_cnt != 1 ||
4447  smtp_state->cmds_idx != 0 ||
4448  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4450  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4451  goto end;
4452  }
4453 
4454  FLOWLOCK_WRLOCK(&f);
4455  /* QUIT Reply */
4456  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4457  STREAM_TOCLIENT, reply5, reply5_len);
4458  if (r != 0) {
4459  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4460  FLOWLOCK_UNLOCK(&f);
4461  goto end;
4462  }
4463  FLOWLOCK_UNLOCK(&f);
4464  if (smtp_state->input_len != 0 ||
4465  smtp_state->cmds_cnt != 0 ||
4466  smtp_state->cmds_idx != 0 ||
4468  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4469  goto end;
4470  }
4471 
4472  result = 1;
4473 end:
4474  if (alp_tctx != NULL)
4476  StreamTcpFreeConfig(true);
4477  FLOW_DESTROY(&f);
4478  return result;
4479 }
4480 
4481 static int SMTPProcessDataChunkTest01(void){
4482  Flow f;
4483  FLOW_INITIALIZE(&f);
4485  MimeDecParseState *state = MimeDecInitParser(&f, NULL);
4486  int ret;
4487  ret = SMTPProcessDataChunk(NULL, 0, state);
4488 
4489  return ret == 0;
4490 }
4491 
4492 
4493 static int SMTPProcessDataChunkTest02(void){
4494  char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72,
4495  0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E,
4496  0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
4497  0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A,
4498  0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61,
4499  0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74,
4500  0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61,
4501  0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
4502  0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73,
4503  0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F,
4504  0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61,
4505  0x73, 0x65, 0x36, 0x34, 0x0D, 0x0A, 0x43, 0x6F,
4506  0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x44, 0x69,
4507  0x73, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F,
4508  0x6E, 0x3A, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63,
4509  0x68, 0x6D, 0x65, 0x6E, 0x74, 0x3B, 0x20, 0x66,
4510  0x69, 0x6C, 0x65, 0x6E, 0x61, 0x6D, 0x65, 0x3D,
4511  0x22, 0x74, 0x65, 0x73, 0x74, 0x2E, 0x65, 0x78,
4512  0x65, 0x22, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x54,
4513  0x56, 0x6F, 0x41, 0x41, 0x46, 0x42, 0x46, 0x41,
4514  0x41, 0x42, 0x4D, 0x41, 0x51, 0x45, 0x41, 0x61,
4515  0x69, 0x70, 0x59, 0x77, 0x77, 0x41, 0x41, 0x41,
4516  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
4517  0x41, 0x41, 0x44, 0x41, 0x51, 0x73, 0x42, 0x43,
4518  0x41, 0x41, 0x42, 0x41, 0x41, 0x43, 0x41, 0x41,
4519  0x41, 0x41, 0x41, 0x41, 0x48, 0x6B, 0x41, 0x41,
4520  0x41, 0x41, 0x4D, 0x41, 0x41, 0x41, 0x41, 0x65,
4521  0x51, 0x41, 0x41, 0x41, 0x41, 0x77, 0x41, 0x41,
4522  0x41, 0x41, 0x41, 0x41, 0x45, 0x41, 0x41, 0x42,
4523  0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
4524  0x41, 0x42, 0x30, 0x41, 0x41, 0x41, 0x41, 0x49,
4525  0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
4526  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
4527  0x41, 0x45, 0x41, 0x41, 0x49, 0x67, 0x41, 0x41,
4528  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4529  0x67, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4530  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4531  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4532  0x41, 0x42, 0x63, 0x58, 0x44, 0x59, 0x32, 0x4C,
4533  0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C,
4534  0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F,
4535  0x41, 0x3D, 0x3D, 0x0D, 0x0A,};
4536 
4537  Flow f;
4538  TcpSession ssn;
4539  memset(&ssn, 0, sizeof(ssn));
4540  FLOW_INITIALIZE(&f);
4541  f.protoctx = &ssn;
4543  MimeDecParseState *state = MimeDecInitParser(&f, NULL);
4544  ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT;
4545  state->body_begin = 1;
4546  int ret;
4547  ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state);
4548 
4549  return ret == 0;
4550 }
4551 
4552 
4553 
4554 static int SMTPProcessDataChunkTest03(void){
4555  char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, };
4556  char mimemsg2[] = {0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, };
4557  char mimemsg3[] = {0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, };
4558  char mimemsg4[] = {0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A, };
4559  char mimemsg5[] = {0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, };
4560  char mimemsg6[] = {0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74, };
4561  char mimemsg7[] = {0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61, };
4562  char mimemsg8[] = {0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, };
4563  char mimemsg9[] = {0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73, };
4564  char mimemsg10[] = {0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F, };
4565  char mimemsg11[] = {0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61, };
4566  char mimemsg12[] = {0x73, 0x65, 0x36, 0x34, 0x0D, 0x0A, 0x43, 0x6F, };
4567 
4568  TcpSession ssn;
4569  memset(&ssn, 0, sizeof(ssn));
4570  Flow f;
4571  FLOW_INITIALIZE(&f);
4572  f.protoctx = &ssn;
4574  MimeDecParseState *state = MimeDecInitParser(&f, NULL);
4575  ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT;
4576  int ret;
4577 
4578  state->body_begin = 1;
4579  ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state);
4580  if(ret) goto end;
4581  state->body_begin = 0;
4582  ret = SMTPProcessDataChunk((uint8_t *)mimemsg2, sizeof(mimemsg2), state);
4583  if(ret) goto end;
4584  ret = SMTPProcessDataChunk((uint8_t *)mimemsg3, sizeof(mimemsg3), state);
4585  if(ret) goto end;
4586  ret = SMTPProcessDataChunk((uint8_t *)mimemsg4, sizeof(mimemsg4), state);
4587  if(ret) goto end;
4588  ret = SMTPProcessDataChunk((uint8_t *)mimemsg5, sizeof(mimemsg5), state);
4589  if(ret) goto end;
4590  ret = SMTPProcessDataChunk((uint8_t *)mimemsg6, sizeof(mimemsg6), state);
4591  if(ret) goto end;
4592  ret = SMTPProcessDataChunk((uint8_t *)mimemsg7, sizeof(mimemsg7), state);
4593  if(ret) goto end;
4594  ret = SMTPProcessDataChunk((uint8_t *)mimemsg8, sizeof(mimemsg8), state);
4595  if(ret) goto end;
4596  ret = SMTPProcessDataChunk((uint8_t *)mimemsg9, sizeof(mimemsg9), state);
4597  if(ret) goto end;
4598  ret = SMTPProcessDataChunk((uint8_t *)mimemsg10, sizeof(mimemsg10), state);
4599  if(ret) goto end;
4600  ret = SMTPProcessDataChunk((uint8_t *)mimemsg11, sizeof(mimemsg11), state);
4601  if(ret) goto end;
4602  state->body_end = 1;
4603  ret = SMTPProcessDataChunk((uint8_t *)mimemsg12, sizeof(mimemsg12), state);
4604  if(ret) goto end;
4605 
4606  end:
4607  return ret == 0;
4608 }
4609 
4610 
4611 static int SMTPProcessDataChunkTest04(void){
4612  char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72, };
4613  char mimemsg2[] = {0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E, };
4614  char mimemsg3[] = {0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, };
4615  char mimemsg4[] = {0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A, };
4616  char mimemsg5[] = {0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, };
4617  char mimemsg6[] = {0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74, };
4618  char mimemsg7[] = {0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61, };
4619  char mimemsg8[] = {0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, };
4620  char mimemsg9[] = {0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73, };
4621  char mimemsg10[] = {0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F, };
4622  char mimemsg11[] = {0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61, };
4623 
4624  TcpSession ssn;
4625  memset(&ssn, 0, sizeof(ssn));
4626  Flow f;
4627  FLOW_INITIALIZE(&f);
4628  f.protoctx = &ssn;
4630  MimeDecParseState *state = MimeDecInitParser(&f, NULL);
4631  ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT;
4632  int ret = MIME_DEC_OK;
4633 
4634  state->body_begin = 1;
4635  if(SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state) != 0) goto end;
4636  if(SMTPProcessDataChunk((uint8_t *)mimemsg2, sizeof(mimemsg2), state) != 0) goto end;
4637  if(SMTPProcessDataChunk((uint8_t *)mimemsg3, sizeof(mimemsg3), state) != 0) goto end;
4638  if(SMTPProcessDataChunk((uint8_t *)mimemsg4, sizeof(mimemsg4), state) != 0) goto end;
4639  if(SMTPProcessDataChunk((uint8_t *)mimemsg5, sizeof(mimemsg5), state) != 0) goto end;
4640  if(SMTPProcessDataChunk((uint8_t *)mimemsg6, sizeof(mimemsg6), state) != 0) goto end;
4641  if(SMTPProcessDataChunk((uint8_t *)mimemsg7, sizeof(mimemsg7), state) != 0) goto end;
4642  state->body_begin = 0;
4643  state->body_end = 1;
4644  if(SMTPProcessDataChunk((uint8_t *)mimemsg8, sizeof(mimemsg8), state) != 0) goto end;
4645  state->body_end = 0;
4646  if(SMTPProcessDataChunk((uint8_t *)mimemsg9, sizeof(mimemsg9), state) != 0) goto end;
4647  if(SMTPProcessDataChunk((uint8_t *)mimemsg10, sizeof(mimemsg10), state) != 0) goto end;
4648  if(SMTPProcessDataChunk((uint8_t *)mimemsg11, sizeof(mimemsg11), state) != 0) goto end;
4649 
4650  end:
4651  return ret == 0;
4652 }
4653 
4654 static int SMTPProcessDataChunkTest05(void){
4655  char mimemsg[] = {0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72,
4656  0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E,
4657  0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
4658  0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A,
4659  0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C,
4660  0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F,
4661  0x41, 0x3D, 0x3D, 0x0D, 0x0A,};
4662 
4663  TcpSession ssn;
4664  memset(&ssn, 0, sizeof(ssn));
4665  Flow f;
4666  int ret;
4667  FLOW_INITIALIZE(&f);
4668  f.protoctx = &ssn;
4670  FAIL_IF(f.alstate == NULL);
4671  MimeDecParseState *state = MimeDecInitParser(&f, NULL);
4672  ((MimeDecEntity *)state->stack->top->data)->ctnt_flags = CTNT_IS_ATTACHMENT;
4673  FAIL_IF(state == NULL);
4674  state->body_begin = 1;
4675  ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state);
4676  FAIL_IF(ret != 0);
4677  state->body_begin = 0;
4678  SMTPState *smtp_state = (SMTPState *)((Flow *)state->data)->alstate;
4679  FileContainer *files = smtp_state->files_ts;
4680  FAIL_IF(files == NULL);
4681  File *file = files->head;
4682  FAIL_IF(file == NULL);
4683  ret = SMTPProcessDataChunk((uint8_t *)mimemsg, sizeof(mimemsg), state);
4684  FAIL_IF(ret != 0);
4685  FAIL_IF((uint32_t)FileDataSize(file) != 106);
4686  SMTPStateFree(smtp_state);
4687  FLOW_DESTROY(&f);
4688  PASS;
4689 }
4690 
4691 #endif /* UNITTESTS */
4692 
4694 {
4695 #ifdef UNITTESTS
4696  UtRegisterTest("SMTPParserTest01", SMTPParserTest01);
4697  UtRegisterTest("SMTPParserTest02", SMTPParserTest02);
4698  UtRegisterTest("SMTPParserTest03", SMTPParserTest03);
4699  UtRegisterTest("SMTPParserTest04", SMTPParserTest04);
4700  UtRegisterTest("SMTPParserTest05", SMTPParserTest05);
4701  UtRegisterTest("SMTPParserTest06", SMTPParserTest06);
4702  UtRegisterTest("SMTPParserTest12", SMTPParserTest12);
4703  UtRegisterTest("SMTPParserTest13", SMTPParserTest13);
4704  UtRegisterTest("SMTPParserTest14", SMTPParserTest14);
4705  UtRegisterTest("SMTPProcessDataChunkTest01", SMTPProcessDataChunkTest01);
4706  UtRegisterTest("SMTPProcessDataChunkTest02", SMTPProcessDataChunkTest02);
4707  UtRegisterTest("SMTPProcessDataChunkTest03", SMTPProcessDataChunkTest03);
4708  UtRegisterTest("SMTPProcessDataChunkTest04", SMTPProcessDataChunkTest04);
4709  UtRegisterTest("SMTPProcessDataChunkTest05", SMTPProcessDataChunkTest05);
4710 #endif /* UNITTESTS */
4711 
4712  return;
4713 }
MpmInitThreadCtx
void MpmInitThreadCtx(MpmThreadCtx *mpm_thread_ctx, uint16_t matcher)
Definition: util-mpm.c:195
PARSE_ERROR
#define PARSE_ERROR
Definition: util-decode-mime.h:77
util-byte.h
MimeDecEntity::ctnt_flags
uint32_t ctnt_flags
Definition: util-decode-mime.h:143
SMTPConfig::content_limit
uint32_t content_limit
Definition: app-layer-smtp.h:97
ConfGetChildValueInt
int ConfGetChildValueInt(const ConfNode *base, const char *name, intmax_t *val)
Definition: conf.c:468
SMTPState_
Definition: app-layer-smtp.h:106
FILE_TRUNCATED
#define FILE_TRUNCATED
Definition: util-file.h:45
MimeDecParseComplete
int MimeDecParseComplete(MimeDecParseState *state)
Called to indicate that the last message line has been processed and the parsing operation is complet...
Definition: util-decode-mime.c:2477
AppLayerParserRegisterGetStateProgressFunc
void AppLayerParserRegisterGetStateProgressFunc(uint8_t ipproto, AppProto alproto, int(*StateGetProgress)(void *alstate, uint8_t direction))
Definition: app-layer-parser.c:503
SMTPState_::consumed
int32_t consumed
Definition: app-layer-smtp.h:128
FileContainer_
Definition: util-file.h:110
len
uint8_t len
Definition: app-layer-dnp3.h:2
SMTP_LINE_BUFFER_LIMIT
#define SMTP_LINE_BUFFER_LIMIT
Definition: app-layer-smtp.c:113
MIME_DEC_OK
@ MIME_DEC_OK
Definition: util-decode-mime.h:83
SMTP_DECODER_EVENT_MIME_MALFORMED_MSG
@ SMTP_DECODER_EVENT_MIME_MALFORMED_MSG
Definition: app-layer-smtp.h:46
MIME_DEC_ERR_MEM
@ MIME_DEC_ERR_MEM
Definition: util-decode-mime.h:86
SMTP_DECODER_EVENT_INVALID_PIPELINED_SEQUENCE
@ SMTP_DECODER_EVENT_INVALID_PIPELINED_SEQUENCE
Definition: app-layer-smtp.h:38
detect-engine.h
SMTPCode
SMTPCode
Definition: app-layer-smtp.c:156
AppLayerProtoDetectPMRegisterPatternCI
int AppLayerProtoDetectPMRegisterPatternCI(uint8_t ipproto, AppProto alproto, const char *pattern, uint16_t depth, uint16_t offset, uint8_t direction)
Registers a case-insensitive pattern for protocol detection.
Definition: app-layer-detect-proto.c:1824
SMTPState_::cmds_cnt
uint16_t cmds_cnt
Definition: app-layer-smtp.h:148
StreamingBufferConfig_::buf_size
uint32_t buf_size
Definition: util-streaming-buffer.h:66
PKT_HAS_FLOW
#define PKT_HAS_FLOW
Definition: decode.h:1175
AppLayerParserRegisterLocalStorageFunc
void AppLayerParserRegisterLocalStorageFunc(uint8_t ipproto, AppProto alproto, void *(*LocalStorageAlloc)(void), void(*LocalStorageFree)(void *))
Definition: app-layer-parser.c:450
SMTP_PARSER_STATE_FIRST_REPLY_SEEN
#define SMTP_PARSER_STATE_FIRST_REPLY_SEEN
Definition: app-layer-smtp.c:84
TAILQ_INIT
#define TAILQ_INIT(head)
Definition: queue.h:263
ANOM_LONG_BOUNDARY
#define ANOM_LONG_BOUNDARY
Definition: util-decode-mime.h:62
flow-util.h
MimeDecConfig::header_value_depth
uint32_t header_value_depth
Definition: util-decode-mime.h:104
SMTPTransaction_::msg_tail
MimeDecEntity * msg_tail
Definition: app-layer-smtp.h:80
SMTP_COMMAND_DATA
#define SMTP_COMMAND_DATA
Definition: app-layer-smtp.c:95
FileContainerAlloc
FileContainer * FileContainerAlloc(void)
allocate a FileContainer
Definition: util-file.c:426
MpmThreadCtx_
Definition: util-mpm.h:46
ConfNode_::val
char * val
Definition: conf.h:34
ConfGetBool
int ConfGetBool(const char *name, int *val)
Retrieve a configuration value as an boolen.
Definition: conf.c:516
stream-tcp.h
SMTPState_::bdat_chunk_idx
uint32_t bdat_chunk_idx
Definition: app-layer-smtp.h:139
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:103
SMTPState_::current_line_len
int32_t current_line_len
Definition: app-layer-smtp.h:125
SMTPState_::orig_input_len
int32_t orig_input_len
Definition: app-layer-smtp.h:119
SMTPState_::current_line
const uint8_t * current_line
Definition: app-layer-smtp.h:123
PrefilterRuleStore_
structure for storing potential rule matches
Definition: util-prefilter.h:32
SMTPState_::current_line_delimiter_len
uint8_t current_line_delimiter_len
Definition: app-layer-smtp.h:126
MimeDecParseState::data
void * data
Definition: util-decode-mime.h:213
MimeDecParseLine
int MimeDecParseLine(const uint8_t *line, const uint32_t len, const uint8_t delim_len, MimeDecParseState *state)
Parse a line of a MIME message and update the parser state.
Definition: util-decode-mime.c:2545
MimeDecEntity::filename
uint8_t * filename
Definition: util-decode-mime.h:146
SMTPTransaction_::mime_state
MimeDecParseState * mime_state
Definition: app-layer-smtp.h:82
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:298
SMTPConfig
Definition: app-layer-smtp.h:93
SMTPTransaction_::msg_head
MimeDecEntity * msg_head
Definition: app-layer-smtp.h:78
SMTP_REPLY_421
@ SMTP_REPLY_421
Definition: app-layer-smtp.c:169
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
Flow_::proto
uint8_t proto
Definition: flow.h:375
AppProto
uint16_t AppProto
Definition: app-layer-protos.h:80
SMTP_DECODER_EVENT_MAX_COMMAND_LINE_LEN_EXCEEDED
@ SMTP_DECODER_EVENT_MAX_COMMAND_LINE_LEN_EXCEEDED
Definition: app-layer-smtp.h:36
SMTPState_::input_len
int32_t input_len
Definition: app-layer-smtp.h:115
AppLayerParserConfParserEnabled
int AppLayerParserConfParserEnabled(const char *ipproto, const char *alproto_name)
check if a parser is enabled in the config Returns enabled always if: were running unittests
Definition: app-layer-parser.c:340
PacketAlertCheck
int PacketAlertCheck(Packet *p, uint32_t sid)
Check if a certain sid alerted, this is used in the test functions.
Definition: detect-engine-alert.c:137
AppLayerParserTriggerRawStreamReassembly
void AppLayerParserTriggerRawStreamReassembly(Flow *f, int direction)
Definition: app-layer-parser.c:1476
StreamTcpReassemblySetMinInspectDepth
void StreamTcpReassemblySetMinInspectDepth(TcpSession *ssn, int direction, uint32_t depth)
Definition: stream-tcp-reassemble.c:2002
STREAMING_BUFFER_CONFIG_INITIALIZER
#define STREAMING_BUFFER_CONFIG_INITIALIZER
Definition: util-streaming-buffer.h:73
SMTPConfig::decode_mime
bool decode_mime
Definition: app-layer-smtp.h:95
Packet_::flags
uint32_t flags
Definition: decode.h:462
ConfGetNode
ConfNode * ConfGetNode(const char *name)
Get a ConfNode by name.
Definition: conf.c:175
threads.h
FILE_STATE_OPENED
@ FILE_STATE_OPENED
Definition: util-file.h:66
ANOM_LONG_LINE
#define ANOM_LONG_LINE
Definition: util-decode-mime.h:59
Flow_
Flow data structure.
Definition: flow.h:353
MimeDecStack::top
MimeDecStackNode * top
Definition: util-decode-mime.h:173
SMTP_REPLY_503
@ SMTP_REPLY_503
Definition: app-layer-smtp.c:178
ConfNodeNew
ConfNode * ConfNodeNew(void)
Allocate a new configuration node.
Definition: conf.c:133
AppLayerEventType
enum AppLayerEventType_ AppLayerEventType
MimeDecEntity::filename_len
uint32_t filename_len
Definition: util-decode-mime.h:145
AppLayerParserRegisterTruncateFunc
void AppLayerParserRegisterTruncateFunc(uint8_t ipproto, AppProto alproto, void(*Truncate)(void *, uint8_t))
Definition: app-layer-parser.c:493
SMTP_REPLY_553
@ SMTP_REPLY_553
Definition: app-layer-smtp.c:183
SMTP_REPLY_500
@ SMTP_REPLY_500
Definition: app-layer-smtp.c:175
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:811
AppLayerParserRegisterStateProgressCompletionStatus
void AppLayerParserRegisterStateProgressCompletionStatus(AppProto alproto, const int ts, const int tc)
Definition: app-layer-parser.c:555
FILE_STORE
#define FILE_STORE
Definition: util-file.h:55
SMTPState_::toserver_last_data_stamp
uint64_t toserver_last_data_stamp
Definition: app-layer-smtp.h:111
SMTPThreadCtx
struct SMTPThreadCtx_ SMTPThreadCtx
AppLayerParserRegisterTxFreeFunc
void AppLayerParserRegisterTxFreeFunc(uint8_t ipproto, AppProto alproto, void(*StateTransactionFree)(void *, uint64_t))
Definition: app-layer-parser.c:514
FileSetTx
int FileSetTx(File *ff, uint64_t txid)
Set the TX id for a file.
Definition: util-file.c:567
FLOW_NOPAYLOAD_INSPECTION
#define FLOW_NOPAYLOAD_INSPECTION
Definition: flow.h:65
SCEnumCharMap_::enum_value
int enum_value
Definition: util-enum.h:29
SMTPState_::tx_cnt
uint64_t tx_cnt
Definition: app-layer-smtp.h:109
TAILQ_FOREACH
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:253
DetectEngineCtxFree
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Definition: detect-engine.c:2433
SMTP_DECODER_EVENT_INVALID_REPLY
@ SMTP_DECODER_EVENT_INVALID_REPLY
Definition: app-layer-smtp.h:34
AppLayerParserThreadCtxFree
void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx)
Destroys the app layer parser thread context obtained using AppLayerParserThreadCtxAlloc().
Definition: app-layer-parser.c:320
SMTPState_::cmds_idx
uint16_t cmds_idx
Definition: app-layer-smtp.h:151
FLOW_PKT_TOSERVER
#define FLOW_PKT_TOSERVER
Definition: flow.h:225
FileContainer_::tail
File * tail
Definition: util-file.h:112
AppLayerDecoderEventsFreeEvents
void AppLayerDecoderEventsFreeEvents(AppLayerDecoderEvents **events)
Definition: app-layer-events.c:130
DE_QUIET
#define DE_QUIET
Definition: detect.h:295
SMTP_REPLY_552
@ SMTP_REPLY_552
Definition: app-layer-smtp.c:182
stream-tcp-reassemble.h
UTHBuildPacket
Packet * UTHBuildPacket(uint8_t *payload, uint16_t payload_len, uint8_t ipproto)
UTHBuildPacket is a wrapper that build packets with default ip and port fields.
Definition: util-unittest-helper.c:337
SMTP_REPLY_550
@ SMTP_REPLY_550
Definition: app-layer-smtp.c:180
SigMatchSignatures
void SigMatchSignatures(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition: detect.c:1790
FILEDATA_CONTENT_LIMIT
#define FILEDATA_CONTENT_LIMIT
Definition: app-layer-smtp.c:61
SMTP_DECODER_EVENT_MIME_INVALID_QP
@ SMTP_DECODER_EVENT_MIME_INVALID_QP
Definition: app-layer-smtp.h:48
SMTP_REPLY_334
@ SMTP_REPLY_334
Definition: app-layer-smtp.c:166
MimeDecSetConfig
void MimeDecSetConfig(MimeDecConfig *config)
Set global config policy.
Definition: util-decode-mime.c:132
TAILQ_INSERT_TAIL
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:295
MimeDecInitParser
MimeDecParseState * MimeDecInitParser(void *data, int(*DataChunkProcessorFunc)(const uint8_t *chunk, uint32_t len, MimeDecParseState *state))
Init the parser by allocating memory for the state and top-level entity.
Definition: util-decode-mime.c:2385
SigCleanSignatures
void SigCleanSignatures(DetectEngineCtx *de_ctx)
Definition: detect-engine-build.c:42
SMTPThreadCtx_
Definition: app-layer-smtp.c:145
Packet_::flowflags
uint8_t flowflags
Definition: decode.h:458
APP_LAYER_PARSER_EOF_TS
#define APP_LAYER_PARSER_EOF_TS
Definition: app-layer-parser.h:42
SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY
#define SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY
Definition: app-layer-smtp.c:86
Flow_::protoctx
void * protoctx
Definition: flow.h:451
FileAppendData
int FileAppendData(FileContainer *ffc, const uint8_t *data, uint32_t data_len)
Store/handle a chunk of file data in the File structure The last file in the FileContainer will be us...
Definition: util-file.c:720
SMTP_REPLY_251
@ SMTP_REPLY_251
Definition: app-layer-smtp.c:163
SMTPState_::direction
uint8_t direction
Definition: app-layer-smtp.h:116
util-unittest.h
APP_LAYER_EVENT_TYPE_TRANSACTION
@ APP_LAYER_EVENT_TYPE_TRANSACTION
Definition: app-layer-events.h:57
ConfNode_::is_seq
int is_seq
Definition: conf.h:36
smtp_decoder_event_table
SCEnumCharMap smtp_decoder_event_table[]
Definition: app-layer-smtp.c:115
SMTPConfig::content_inspect_min_size
uint32_t content_inspect_min_size
Definition: app-layer-smtp.h:98
util-unittest-helper.h
SMTP_REPLY_502
@ SMTP_REPLY_502
Definition: app-layer-smtp.c:177
TcpSession_::flags
uint16_t flags
Definition: stream-tcp-private.h:269
FLOWLOCK_UNLOCK
#define FLOWLOCK_UNLOCK(fb)
Definition: flow.h:270
File_::sb
StreamingBuffer * sb
Definition: util-file.h:79
SMTPConfig::raw_extraction
bool raw_extraction
Definition: app-layer-smtp.h:101
SMTP_DECODER_EVENT_UNPARSABLE_CONTENT
@ SMTP_DECODER_EVENT_UNPARSABLE_CONTENT
Definition: app-layer-smtp.h:58
util-memcmp.h
SMTP_DECODER_EVENT_MIME_LONG_LINE
@ SMTP_DECODER_EVENT_MIME_LONG_LINE
Definition: app-layer-smtp.h:49
MpmInitCtx
void MpmInitCtx(MpmCtx *mpm_ctx, uint8_t matcher)
Definition: util-mpm.c:200
MimeDecParseState::body_begin
int body_begin
Definition: util-decode-mime.h:210
SMTP_DECODER_EVENT_TLS_REJECTED
@ SMTP_DECODER_EVENT_TLS_REJECTED
Definition: app-layer-smtp.h:41
SC_ERR_SIZE_PARSE
@ SC_ERR_SIZE_PARSE
Definition: util-error.h:230
ANOM_MALFORMED_MSG
#define ANOM_MALFORMED_MSG
Definition: util-decode-mime.h:61
app-layer-detect-proto.h
StreamTcpInitConfig
void StreamTcpInitConfig(bool)
To initialize the stream global configuration data.
Definition: stream-tcp.c:357
FLOW_INITIALIZE
#define FLOW_INITIALIZE(f)
Definition: flow-util.h:39
SMTP_REPLY_504
@ SMTP_REPLY_504
Definition: app-layer-smtp.c:179
AppLayerParserStateIssetFlag
int AppLayerParserStateIssetFlag(AppLayerParserState *pstate, uint8_t flag)
Definition: app-layer-parser.c:1701
SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME
@ SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME
Definition: app-layer-smtp.h:51
SMTP_COMMAND_DATA_MODE
#define SMTP_COMMAND_DATA_MODE
Definition: app-layer-smtp.c:101
SMTP_COMMAND_STARTTLS
#define SMTP_COMMAND_STARTTLS
Definition: app-layer-smtp.c:94
APP_LAYER_INCOMPLETE
#define APP_LAYER_INCOMPLETE(c, n)
Definition: app-layer-parser.h:99
TAILQ_REMOVE
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:313
decode.h
util-debug.h
SMTP_MPM
#define SMTP_MPM
Definition: app-layer-smtp.c:150
TAILQ_FIRST
#define TAILQ_FIRST(head)
Definition: queue.h:251
MimeDecConfig::extract_urls_schemes
ConfNode * extract_urls_schemes
Definition: util-decode-mime.h:100
AppLayerParserState_
Definition: app-layer-parser.c:155
SC_ERR_CONF_YAML_ERROR
@ SC_ERR_CONF_YAML_ERROR
Definition: util-error.h:274
PASS
#define PASS
Pass the test.
Definition: util-unittest.h:105
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:17
SMTP_REPLY_235
@ SMTP_REPLY_235
Definition: app-layer-smtp.c:161
SMTP_REPLY_551
@ SMTP_REPLY_551
Definition: app-layer-smtp.c:181
FileFlowToFlags
uint16_t FileFlowToFlags(const Flow *flow, uint8_t direction)
Definition: util-file.c:234
DetectEngineThreadCtx_
Definition: detect.h:1060
SC_FILENAME_MAX
#define SC_FILENAME_MAX
Definition: util-file.h:62
FLOWFILE_NO_STORE_TS
#define FLOWFILE_NO_STORE_TS
Definition: flow.h:126
SMTP_COMMAND_RSET
#define SMTP_COMMAND_RSET
Definition: app-layer-smtp.c:104
SMTPState_::helo
uint8_t * helo
Definition: app-layer-smtp.h:155
ALPROTO_SMTP
@ ALPROTO_SMTP
Definition: app-layer-protos.h:32
SMTP_DECODER_EVENT_MIME_PARSE_FAILED
@ SMTP_DECODER_EVENT_MIME_PARSE_FAILED
Definition: app-layer-smtp.h:45
SMTPTransaction_::done
int done
Definition: app-layer-smtp.h:76
res
PoolThreadReserved res
Definition: stream-tcp-private.h:0
alp_tctx
AppLayerParserThreadCtx * alp_tctx
Definition: fuzz_applayerparserparse.c:20
FLOWLOCK_WRLOCK
#define FLOWLOCK_WRLOCK(fb)
Definition: flow.h:267
MimeDecParseState::stack
MimeDecStack * stack
Definition: util-decode-mime.h:194
AppLayerParserRegisterGetFilesFunc
void AppLayerParserRegisterGetFilesFunc(uint8_t ipproto, AppProto alproto, FileContainer *(*StateGetFiles)(void *, uint8_t))
Definition: app-layer-parser.c:464
SCEnter
#define SCEnter(...)
Definition: util-debug.h:300
SMTPTransaction_::tx_data
AppLayerTxData tx_data
Definition: app-layer-smtp.h:74
SMTPState_::parser_state
uint8_t parser_state
Definition: app-layer-smtp.h:133
FileContainer_::head
File * head
Definition: util-file.h:111
SMTP_REPLY_455
@ SMTP_REPLY_455
Definition: app-layer-smtp.c:173
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
SMTPTransaction_::mail_from
uint8_t * mail_from
Definition: app-layer-smtp.h:85
SMTPState_::input
const uint8_t * input
Definition: app-layer-smtp.h:114
FileTrackedSize
uint64_t FileTrackedSize(const File *file)
get the size of the file
Definition: util-file.c:311
AppLayerParserRegisterStateFuncs
void AppLayerParserRegisterStateFuncs(uint8_t ipproto, AppProto alproto, void *(*StateAlloc)(void *, AppProto), void(*StateFree)(void *))
Definition: app-layer-parser.c:437
FILEDATA_CONTENT_INSPECT_MIN_SIZE
#define FILEDATA_CONTENT_INSPECT_MIN_SIZE
Definition: app-layer-smtp.c:63
SMTPState_::curr_tx
SMTPTransaction * curr_tx
Definition: app-layer-smtp.h:107
SMTP_COMMAND_BDAT
#define SMTP_COMMAND_BDAT
Definition: app-layer-smtp.c:96
SMTP_REPLY_211
@ SMTP_REPLY_211
Definition: app-layer-smtp.c:157
SMTP_REPLY_220
@ SMTP_REPLY_220
Definition: app-layer-smtp.c:159
app-layer-parser.h
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:281
smtp_config
SMTPConfig smtp_config
Definition: app-layer-smtp.c:222
PmqReset
void PmqReset(PrefilterRuleStore *)
Reset a Pmq for reusage. Meant to be called after a single search.
Definition: util-prefilter.c:101
SigGroupCleanup
int SigGroupCleanup(DetectEngineCtx *de_ctx)
Definition: detect-engine-build.c:2016
SCReturn
#define SCReturn
Definition: util-debug.h:302
SMTP_RAW_EXTRACTION_DEFAULT_VALUE
#define SMTP_RAW_EXTRACTION_DEFAULT_VALUE
Definition: app-layer-smtp.c:68
stream.h
AppLayerParserRegisterProtocolUnittests
void AppLayerParserRegisterProtocolUnittests(uint8_t ipproto, AppProto alproto, void(*RegisterUnittests)(void))
Definition: app-layer-parser.c:1798
SMTP_REPLY_252
@ SMTP_REPLY_252
Definition: app-layer-smtp.c:164
Packet_
Definition: decode.h:427
SMTPTransaction_
Definition: app-layer-smtp.h:70
stream-tcp-private.h
SMTP_REPLY_250
@ SMTP_REPLY_250
Definition: app-layer-smtp.c:162
APP_LAYER_PARSER_EOF_TC
#define APP_LAYER_PARSER_EOF_TC
Definition: app-layer-parser.h:43
conf.h
SMTP_REPLY_555
@ SMTP_REPLY_555
Definition: app-layer-smtp.c:185
StreamingBufferCompareRawData
int StreamingBufferCompareRawData(const StreamingBuffer *sb, const uint8_t *rawdata, uint32_t rawdata_len)
Definition: util-streaming-buffer.c:872
MpmTableElmt_::Prepare
int(* Prepare)(struct MpmCtx_ *)
Definition: util-mpm.h:164
AppLayerParserRegisterGetEventInfo
void AppLayerParserRegisterGetEventInfo(uint8_t ipproto, AppProto alproto, int(*StateGetEventInfo)(const char *event_name, int *event_id, AppLayerEventType *event_type))
Definition: app-layer-parser.c:592
FileOpenFileWithId
int FileOpenFileWithId(FileContainer *ffc, const StreamingBufferConfig *sbcfg, uint32_t track_id, const uint8_t *name, uint16_t name_len, const uint8_t *data, uint32_t data_len, uint16_t flags)
Open a new File.
Definition: util-file.c:920
SMTPState_::current_command
uint8_t current_command
Definition: app-layer-smtp.h:135
File_::name
uint8_t * name
Definition: util-file.h:85
SCReturnPtr
#define SCReturnPtr(x, type)
Definition: util-debug.h:316
SMTP_PARSER_STATE_COMMAND_DATA_MODE
#define SMTP_PARSER_STATE_COMMAND_DATA_MODE
Definition: app-layer-smtp.c:78
detect-engine-state.h
Data structures and function prototypes for keeping state for the detection engine.
AppLayerProtoDetectRegisterProtocol
void AppLayerProtoDetectRegisterProtocol(AppProto alproto, const char *alproto_name)
Registers a protocol for protocol detection phase.
Definition: app-layer-detect-proto.c:1901
MimeDecConfig::decode_base64
bool decode_base64
Definition: util-decode-mime.h:97
rawmsgname
#define rawmsgname
Definition: app-layer-smtp.c:1110
SMTP_COMMAND_BUFFER_STEPS
#define SMTP_COMMAND_BUFFER_STEPS
Definition: app-layer-smtp.c:71
SMTPTransaction_::mail_from_len
uint16_t mail_from_len
Definition: app-layer-smtp.h:86
MpmTableElmt_::Search
uint32_t(* Search)(const struct MpmCtx_ *, struct MpmThreadCtx_ *, PrefilterRuleStore *, const uint8_t *, uint32_t)
Definition: util-mpm.h:165
FILE_NOMD5
#define FILE_NOMD5
Definition: util-file.h:47
RunmodeIsUnittests
int RunmodeIsUnittests(void)
Definition: suricata.c:271
SMTP_DECODER_EVENT_MIME_INVALID_BASE64
@ SMTP_DECODER_EVENT_MIME_INVALID_BASE64
Definition: app-layer-smtp.h:47
SCLogInfo
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:217
SMTP_REPLY_554
@ SMTP_REPLY_554
Definition: app-layer-smtp.c:184
SMTPStateAlloc
void * SMTPStateAlloc(void *orig_state, AppProto proto_orig)
Definition: app-layer-smtp.c:1420
AppLayerParserRegisterParser
int AppLayerParserRegisterParser(uint8_t ipproto, AppProto alproto, uint8_t direction, AppLayerParserFPtr Parser)
Register app layer parser for the protocol.
Definition: app-layer-parser.c:398
DetectEngineStateFree
void DetectEngineStateFree(DetectEngineState *state)
Frees a DetectEngineState object.
Definition: detect-engine-state.c:174
DETECT_ENGINE_STATE_FLAG_FILE_NEW
#define DETECT_ENGINE_STATE_FLAG_FILE_NEW
Definition: detect-engine-state.h:71
decode-events.h
ANOM_LONG_HEADER_VALUE
#define ANOM_LONG_HEADER_VALUE
Definition: util-decode-mime.h:58
FileDataSize
uint64_t FileDataSize(const File *file)
get the size of the file data
Definition: util-file.c:294
SMTP_REPLY_452
@ SMTP_REPLY_452
Definition: app-layer-smtp.c:172
SigGroupBuild
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
Definition: detect-engine-build.c:1948
SMTPThreadCtx_::smtp_mpm_thread_ctx
MpmThreadCtx * smtp_mpm_thread_ctx
Definition: app-layer-smtp.c:146
MimeDecConfig::log_url_scheme
bool log_url_scheme
Definition: util-decode-mime.h:102
SCRealloc
#define SCRealloc(ptr, sz)
Definition: util-mem.h:50
AppLayerParserThreadCtxAlloc
AppLayerParserThreadCtx * AppLayerParserThreadCtxAlloc(void)
Gets a new app layer protocol's parser thread context.
Definition: app-layer-parser.c:299
SMTP_COMMAND_OTHER_CMD
#define SMTP_COMMAND_OTHER_CMD
Definition: app-layer-smtp.c:103
AppLayerParserRegisterGetTx
void AppLayerParserRegisterGetTx(uint8_t ipproto, AppProto alproto, void *(StateGetTx)(void *alstate, uint64_t tx_id))
Definition: app-layer-parser.c:536
SMTPString_::len
uint16_t len
Definition: app-layer-smtp.h:65
ConfNodeLookupChild
ConfNode * ConfNodeLookupChild(const ConfNode *node, const char *name)
Lookup a child configuration node by name.
Definition: conf.c:814
SMTPState_::helo_len
uint16_t helo_len
Definition: app-layer-smtp.h:154
util-mem.h
MimeDecParseState::msg
MimeDecEntity * msg
Definition: util-decode-mime.h:193
SMTPState_::toserver_data_count
uint64_t toserver_data_count
Definition: app-layer-smtp.h:110
File_
Definition: util-file.h:75
APP_LAYER_OK
#define APP_LAYER_OK
Definition: app-layer-parser.h:87
DetectEngineAppendSig
Signature * DetectEngineAppendSig(DetectEngineCtx *de_ctx, const char *sigstr)
Parse and append a Signature into the Detection Engine Context signature list.
Definition: detect-parse.c:2420
AppLayerRequestProtocolTLSUpgrade
void AppLayerRequestProtocolTLSUpgrade(Flow *f)
request applayer to wrap up this protocol and rerun protocol detection with expectation of TLS....
Definition: app-layer-detect-proto.c:1981
ANOM_LONG_ENC_LINE
#define ANOM_LONG_ENC_LINE
Definition: util-decode-mime.h:60
SCMapEnumValueToName
const char * SCMapEnumValueToName(int enum_value, SCEnumCharMap *table)
Maps an enum value to a string name, from the supplied table.
Definition: util-enum.c:68
Packet_::flow
struct Flow_ * flow
Definition: decode.h:464
SCReturnStruct
#define SCReturnStruct(x)
Definition: util-debug.h:320
SMTPState_::cmds
uint8_t * cmds
Definition: app-layer-smtp.h:144
DetectEngineThreadCtxInit
TmEcode DetectEngineThreadCtxInit(ThreadVars *, void *, void **)
initialize thread specific detection engine context
Definition: detect-engine.c:3142
FAIL_IF
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
Definition: util-unittest.h:71
util-mpm.h
StreamTcpFreeConfig
void StreamTcpFreeConfig(bool quiet)
Definition: stream-tcp.c:662
SMTPProcessDataChunk
int SMTPProcessDataChunk(const uint8_t *chunk, uint32_t len, MimeDecParseState *state)
Definition: app-layer-smtp.c:457
SCMapEnumNameToValue
int SCMapEnumNameToValue(const char *enum_name, SCEnumCharMap *table)
Maps a string name to an enum value from the supplied table. Please specify the last element of any m...
Definition: util-enum.c:40
SMTP_DECODER_EVENT_MIME_LONG_ENC_LINE
@ SMTP_DECODER_EVENT_MIME_LONG_ENC_LINE
Definition: app-layer-smtp.h:50
flags
uint8_t flags
Definition: decode-gre.h:0
AppLayerParserParse
int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alproto, uint8_t flags, const uint8_t *input, uint32_t input_len)
Definition: app-layer-parser.c:1237
SMTP_DECODER_EVENT_MAX_REPLY_LINE_LEN_EXCEEDED
@ SMTP_DECODER_EVENT_MAX_REPLY_LINE_LEN_EXCEEDED
Definition: app-layer-smtp.h:37
suricata-common.h
DetectEngineThreadCtxDeinit
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *, void *)
Definition: detect-engine.c:3354
SMTPTransaction_::tx_id
uint64_t tx_id
Definition: app-layer-smtp.h:72
SMTP_DECODER_EVENT_BDAT_CHUNK_LEN_EXCEEDED
@ SMTP_DECODER_EVENT_BDAT_CHUNK_LEN_EXCEEDED
Definition: app-layer-smtp.h:39
SMTP_REPLY_214
@ SMTP_REPLY_214
Definition: app-layer-smtp.c:158
SCEnumCharMap_
Definition: util-enum.h:27
SMTPState_::files_ts
FileContainer * files_ts
Definition: app-layer-smtp.h:159
AppLayerDecoderEventsSetEventRaw
void AppLayerDecoderEventsSetEventRaw(AppLayerDecoderEvents **sevents, uint8_t event)
Set an app layer decoder event.
Definition: app-layer-events.c:89
SMTPState_::bdat_chunk_len
uint32_t bdat_chunk_len
Definition: app-layer-smtp.h:137
ConfNode_::name
char * name
Definition: conf.h:33
MIME_DEC_ERR_STATE
@ MIME_DEC_ERR_STATE
Definition: util-decode-mime.h:88
PmqFree
void PmqFree(PrefilterRuleStore *)
Cleanup and free a Pmq.
Definition: util-prefilter.c:125
SMTP_DECODER_EVENT_DUPLICATE_FIELDS
@ SMTP_DECODER_EVENT_DUPLICATE_FIELDS
Definition: app-layer-smtp.h:57
SCLogError
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:257
SMTP_PARSER_STATE_PIPELINING_SERVER
#define SMTP_PARSER_STATE_PIPELINING_SERVER
Definition: app-layer-smtp.c:88
FileSetInspectSizes
void FileSetInspectSizes(File *file, const uint32_t win, const uint32_t min)
Definition: util-file.c:796
ANOM_INVALID_QP
#define ANOM_INVALID_QP
Definition: util-decode-mime.h:56
SMTPString_
Definition: app-layer-smtp.h:63
MimeDecConfig::decode_quoted_printable
bool decode_quoted_printable
Definition: util-decode-mime.h:98
SCStrdup
#define SCStrdup(s)
Definition: util-mem.h:56
FatalError
#define FatalError(x,...)
Definition: util-debug.h:532
AppLayerParserRegisterTxDataFunc
void AppLayerParserRegisterTxDataFunc(uint8_t ipproto, AppProto alproto, AppLayerTxData *(*GetTxData)(void *tx))
Definition: app-layer-parser.c:604
ConfGetChildValueBool
int ConfGetChildValueBool(const ConfNode *base, const char *name, int *val)
Definition: conf.c:529
MimeDecConfig::extract_urls
bool extract_urls
Definition: util-decode-mime.h:99
ParseSizeStringU32
int ParseSizeStringU32(const char *size, uint32_t *res)
Definition: util-misc.c:183
util-validate.h
ANOM_LONG_FILENAME
#define ANOM_LONG_FILENAME
Definition: util-decode-mime.h:63
MimeDecParseState::body_end
int body_end
Definition: util-decode-mime.h:211
MimeDecParseState
Structure contains the current state of the MIME parser.
Definition: util-decode-mime.h:192
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
str
#define str(s)
Definition: suricata-common.h:272
MpmTableElmt_::DestroyCtx
void(* DestroyCtx)(struct MpmCtx_ *)
Definition: util-mpm.h:148
SCLogWarning
#define SCLogWarning(err_code,...)
Macro used to log WARNING messages.
Definition: util-debug.h:244
SCFree
#define SCFree(p)
Definition: util-mem.h:61
SMTP_REPLY_221
@ SMTP_REPLY_221
Definition: app-layer-smtp.c:160
ConfNode_
Definition: conf.h:32
ANOM_INVALID_BASE64
#define ANOM_INVALID_BASE64
Definition: util-decode-mime.h:55
Flow_::alstate
void * alstate
Definition: flow.h:486
SC_ERR_FATAL
@ SC_ERR_FATAL
Definition: util-error.h:203
MimeDecFreeEntity
void MimeDecFreeEntity(MimeDecEntity *entity)
Frees a mime entity tree.
Definition: util-decode-mime.c:181
SMTPConfig::mime_config
MimeDecConfig mime_config
Definition: app-layer-smtp.h:96
Flow_::flags
uint32_t flags
Definition: flow.h:431
smtp_reply_map
SCEnumCharMap smtp_reply_map[]
Definition: app-layer-smtp.c:188
PmqSetup
int PmqSetup(PrefilterRuleStore *)
Setup a pmq.
Definition: util-prefilter.c:36
detect-parse.h
AppLayerParserRegisterGetEventInfoById
void AppLayerParserRegisterGetEventInfoById(uint8_t ipproto, AppProto alproto, int(*StateGetEventInfoById)(int event_id, const char **event_name, AppLayerEventType *event_type))
Definition: app-layer-parser.c:570
FILEDATA_CONTENT_INSPECT_WINDOW
#define FILEDATA_CONTENT_INSPECT_WINDOW
Definition: app-layer-smtp.c:65
Signature_
Signature container.
Definition: detect.h:548
SMTP_REPLY_450
@ SMTP_REPLY_450
Definition: app-layer-smtp.c:170
SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE
@ SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE
Definition: app-layer-smtp.h:40
FileTruncateAllOpenFiles
void FileTruncateAllOpenFiles(FileContainer *fc)
Definition: util-file.c:1220
SMTP_DECODER_EVENT_UNABLE_TO_MATCH_REPLY_WITH_REQUEST
@ SMTP_DECODER_EVENT_UNABLE_TO_MATCH_REPLY_WITH_REQUEST
Definition: app-layer-smtp.h:35
ALPROTO_UNKNOWN
@ ALPROTO_UNKNOWN
Definition: app-layer-protos.h:29
FLOW_PKT_ESTABLISHED
#define FLOW_PKT_ESTABLISHED
Definition: flow.h:227
DetectEngineCtxInit
DetectEngineCtx * DetectEngineCtxInit(void)
Definition: detect-engine.c:2394
SMTP_REPLY_451
@ SMTP_REPLY_451
Definition: app-layer-smtp.c:171
RegisterSMTPParsers
void RegisterSMTPParsers(void)
Register the SMTP Protocol parser.
Definition: app-layer-smtp.c:1731
mpm_table
MpmTableElmt mpm_table[MPM_TABLE_SIZE]
Definition: util-mpm.c:48
app-layer-protos.h
SC_ERR_MEM_ALLOC
@ SC_ERR_MEM_ALLOC
Definition: util-error.h:31
STREAMTCP_FLAG_APP_LAYER_DISABLED
#define STREAMTCP_FLAG_APP_LAYER_DISABLED
Definition: stream-tcp-private.h:188
STREAMTCP_STREAM_FLAG_NOREASSEMBLY
#define STREAMTCP_STREAM_FLAG_NOREASSEMBLY
Definition: stream-tcp-private.h:200
suricata.h
AppLayerParserRegisterGetTxCnt
void AppLayerParserRegisterGetTxCnt(uint8_t ipproto, AppProto alproto, uint64_t(*StateGetTxCnt)(void *alstate))
Definition: app-layer-parser.c:525
APP_LAYER_ERROR
#define APP_LAYER_ERROR
Definition: app-layer-parser.h:91
SC_ERR_INVALID_ENUM_MAP
@ SC_ERR_INVALID_ENUM_MAP
Definition: util-error.h:45
SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED
@ SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED
Definition: app-layer-smtp.h:42
SMTPConfig::sbcfg
StreamingBufferConfig sbcfg
Definition: app-layer-smtp.h:103
MimeDecEntity::next
struct MimeDecEntity * next
Definition: util-decode-mime.h:151
SMTP_REPLY_501
@ SMTP_REPLY_501
Definition: app-layer-smtp.c:176
ANOM_LONG_HEADER_NAME
#define ANOM_LONG_HEADER_NAME
Definition: util-decode-mime.h:57
FILE_USE_DETECT
#define FILE_USE_DETECT
Definition: util-file.h:58
SMTP_DECODER_EVENT_MIME_LONG_FILENAME
@ SMTP_DECODER_EVENT_MIME_LONG_FILENAME
Definition: app-layer-smtp.h:54
SMTP_DECODER_EVENT_MIME_BOUNDARY_TOO_LONG
@ SMTP_DECODER_EVENT_MIME_BOUNDARY_TOO_LONG
Definition: app-layer-smtp.h:53
CTNT_IS_ATTACHMENT
#define CTNT_IS_ATTACHMENT
Definition: util-decode-mime.h:43
DetectEngineCtx_::flags
uint8_t flags
Definition: detect.h:812
SMTPString_::str
uint8_t * str
Definition: app-layer-smtp.h:64
MpmTableElmt_::DestroyThreadCtx
void(* DestroyThreadCtx)(struct MpmCtx_ *, struct MpmThreadCtx_ *)
Definition: util-mpm.h:149
SMTPState_::file_track_id
uint32_t file_track_id
Definition: app-layer-smtp.h:160
AppLayerParserThreadCtx_
Definition: app-layer-parser.c:86
app-layer-smtp.h
SMTP_DECODER_EVENT_TRUNCATED_LINE
@ SMTP_DECODER_EVENT_TRUNCATED_LINE
Definition: app-layer-smtp.h:60
FileContainerFree
void FileContainerFree(FileContainer *ffc)
Free a FileContainer.
Definition: util-file.c:462
FlowChangeProto
int FlowChangeProto(Flow *f)
Check if change proto flag is set for flow.
Definition: flow.c:212
MpmCtx_
Definition: util-mpm.h:88
TcpSession_
Definition: stream-tcp-private.h:260
SMTPState_::cmds_buffer_len
uint16_t cmds_buffer_len
Definition: app-layer-smtp.h:146
SMTPParserRegisterTests
void SMTPParserRegisterTests(void)
Definition: app-layer-smtp.c:4693
util-misc.h
SCEnumCharMap_::enum_name
const char * enum_name
Definition: util-enum.h:28
MimeDecDeInitParser
void MimeDecDeInitParser(MimeDecParseState *state)
De-Init parser by freeing up any residual memory.
Definition: util-decode-mime.c:2441
FILE_NOMAGIC
#define FILE_NOMAGIC
Definition: util-file.h:46
msg
const char * msg
Definition: app-layer-htp.c:562
Flow_::file_flags
uint16_t file_flags
Definition: flow.h:433
Flow_::alproto
AppProto alproto
application level protocol
Definition: flow.h:460
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:304
MimeDecEntity
This represents the MIME Entity (or also top level message) in a child-sibling tree.
Definition: util-decode-mime.h:137
MimeDecParseState::state_flag
uint8_t state_flag
Definition: util-decode-mime.h:207
MpmAddPatternCI
int MpmAddPatternCI(struct MpmCtx_ *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags)
Definition: util-mpm.c:250
AppLayerProtoDetectConfProtoDetectionEnabled
int AppLayerProtoDetectConfProtoDetectionEnabled(const char *ipproto, const char *alproto)
Given a protocol name, checks if proto detection is enabled in the conf file.
Definition: app-layer-detect-proto.c:2070
FileCloseFile
int FileCloseFile(FileContainer *ffc, const uint8_t *data, uint32_t data_len, uint16_t flags)
Close a File.
Definition: util-file.c:1008
MimeDecConfig::body_md5
bool body_md5
Definition: util-decode-mime.h:103
SMTPParserCleanup
void SMTPParserCleanup(void)
Free memory allocated for global SMTP parser state.
Definition: app-layer-smtp.c:1785
SMTPConfig::content_inspect_window
uint32_t content_inspect_window
Definition: app-layer-smtp.h:99
SMTPThreadCtx_::pmq
PrefilterRuleStore * pmq
Definition: app-layer-smtp.c:147
SMTP_REPLY_354
@ SMTP_REPLY_354
Definition: app-layer-smtp.c:167
SCLogDebugEnabled
int SCLogDebugEnabled(void)
Returns whether debug messages are enabled to be logged or not.
Definition: util-debug.c:647
SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE
@ SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE
Definition: app-layer-smtp.h:52
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:111
FLOW_DESTROY
#define FLOW_DESTROY(f)
Definition: flow-util.h:130
debug.h
SMTPState_::discard_till_lf
bool discard_till_lf
Definition: app-layer-smtp.h:130
MIME_DEC_ERR_DATA
@ MIME_DEC_ERR_DATA
Definition: util-decode-mime.h:85
MimeDecStackNode::data
MimeDecEntity * data
Definition: util-decode-mime.h:161
PKT_STREAM_EST
#define PKT_STREAM_EST
Definition: decode.h:1172
app-layer.h
PrefilterRuleStore_::rule_id_array
SigIntId * rule_id_array
Definition: util-prefilter.h:36
UTHFreePackets
void UTHFreePackets(Packet **p, int numpkts)
UTHFreePackets: function to release the allocated data from UTHBuildPacket and the packet itself.
Definition: util-unittest-helper.c:468