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