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