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