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