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