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