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