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