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