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  /* the reply code has to contain at least 3 bytes, to hold the 3 digit
864  * reply code */
865  if (line->len < 3) {
866  /* decoder event */
867  SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY);
868  return -1;
869  }
870 
871  if (line->len >= 4) {
873  if (line->buf[3] != '-') {
875  }
876  } else {
877  if (line->buf[3] == '-') {
879  }
880  }
881  } else {
884  }
885  }
886 
887  /* I don't like this pmq reset here. We'll devise a method later, that
888  * should make the use of the mpm very efficient */
889  PmqReset(td->pmq);
890  int mpm_cnt = mpm_table[SMTP_MPM].Search(
891  smtp_mpm_ctx, td->smtp_mpm_thread_ctx, td->pmq, line->buf, 3);
892  if (mpm_cnt == 0) {
893  /* set decoder event - reply code invalid */
894  SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY);
895  SCLogDebug("invalid reply code %02x %02x %02x", line->buf[0], line->buf[1], line->buf[2]);
896  SCReturnInt(-1);
897  }
898  enum SMTPCode reply_code = smtp_reply_map[td->pmq->rule_id_array[0]].enum_value;
899  SCLogDebug("REPLY: reply_code %u / %s", reply_code,
900  smtp_reply_map[reply_code].enum_name);
901 
902  if (state->cmds_idx == state->cmds_cnt) {
904  /* the first server reply can be a multiline message. Let's
905  * flag the fact that we have seen the first reply only at the end
906  * of a multiline reply
907  */
910  if (reply_code == SMTP_REPLY_220)
911  SCReturnInt(0);
912  else {
913  SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY);
914  SCReturnInt(0);
915  }
916  } else {
917  /* decoder event - unable to match reply with request */
918  SCLogDebug("unable to match reply with request");
919  SCReturnInt(0);
920  }
921  }
922 
923  if (state->cmds_cnt == 0) {
924  /* reply but not a command we have stored, fall through */
925  } else if (IsReplyToCommand(state, SMTP_COMMAND_STARTTLS)) {
926  if (reply_code == SMTP_REPLY_220) {
927  /* we are entering STARTTLS data mode */
930  SMTPSetEvent(state, SMTP_DECODER_EVENT_FAILED_PROTOCOL_CHANGE);
931  }
932  if (state->curr_tx) {
933  SMTPTransactionComplete(state);
934  }
935  } else {
936  /* decoder event */
937  SMTPSetEvent(state, SMTP_DECODER_EVENT_TLS_REJECTED);
938  }
939  } else if (IsReplyToCommand(state, SMTP_COMMAND_DATA)) {
940  if (reply_code == SMTP_REPLY_354) {
941  /* Next comes the mail for the DATA command in toserver direction */
943  } else {
944  /* decoder event */
946  // reset data mode if we had entered it prematurely
948  }
949  SMTPSetEvent(state, SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED);
950  }
951  } else if (IsReplyToCommand(state, SMTP_COMMAND_RSET)) {
952  if (reply_code == SMTP_REPLY_250 && state->curr_tx &&
954  SMTPTransactionComplete(state);
955  }
956  } else {
957  /* we don't care for any other command for now */
958  }
959 
960  /* if it is a multi-line reply, we need to move the index only once for all
961  * the line of the reply. We unset the multiline flag on the last
962  * line of the multiline reply, following which we increment the index */
964  state->cmds_idx++;
965  } else if (state->parser_state & SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
966  /* we check if the server is indicating pipelining support */
967  if (reply_code == SMTP_REPLY_250 && line->len == 14 &&
968  SCMemcmpLowercase("pipelining", line->buf + 4, 10) == 0) {
970  }
971  }
972 
973  /* if we have matched all the buffered commands, reset the cnt and index */
974  if (state->cmds_idx == state->cmds_cnt) {
975  state->cmds_cnt = 0;
976  state->cmds_idx = 0;
977  }
978 
979  return 0;
980 }
981 
982 static int SMTPParseCommandBDAT(SMTPState *state, const SMTPLine *line)
983 {
984  SCEnter();
985 
986  int i = 4;
987  while (i < line->len) {
988  if (line->buf[i] != ' ') {
989  break;
990  }
991  i++;
992  }
993  if (i == 4) {
994  /* decoder event */
995  return -1;
996  }
997  if (i == line->len) {
998  /* decoder event */
999  return -1;
1000  }
1001  // copy in temporary null-terminated buffer for conversion
1002  char strbuf[24];
1003  int len = 23;
1004  if (line->len - i < len) {
1005  len = line->len - i;
1006  }
1007  memcpy(strbuf, line->buf + i, len);
1008  strbuf[len] = '\0';
1009  if (ByteExtractStringUint32(&state->bdat_chunk_len, 10, 0, strbuf) < 0) {
1010  /* decoder event */
1011  return -1;
1012  }
1013 
1014  return 0;
1015 }
1016 
1017 static int SMTPParseCommandWithParam(SMTPState *state, const SMTPLine *line, uint8_t prefix_len,
1018  uint8_t **target, uint16_t *target_len)
1019 {
1020  int i = prefix_len + 1;
1021 
1022  while (i < line->len) {
1023  if (line->buf[i] != ' ') {
1024  break;
1025  }
1026  i++;
1027  }
1028 
1029  /* rfc1870: with the size extension the mail from can be followed by an option.
1030  We use the space separator to detect it. */
1031  int spc_i = i;
1032  while (spc_i < line->len) {
1033  if (line->buf[spc_i] == ' ') {
1034  break;
1035  }
1036  spc_i++;
1037  }
1038 
1039  *target = SCMalloc(spc_i - i + 1);
1040  if (*target == NULL)
1041  return -1;
1042  memcpy(*target, line->buf + i, spc_i - i);
1043  (*target)[spc_i - i] = '\0';
1044  if (spc_i - i > UINT16_MAX) {
1045  *target_len = UINT16_MAX;
1047  } else {
1048  *target_len = (uint16_t)(spc_i - i);
1049  }
1050 
1051  return 0;
1052 }
1053 
1054 static int SMTPParseCommandHELO(SMTPState *state, const SMTPLine *line)
1055 {
1056  if (state->helo) {
1057  SMTPSetEvent(state, SMTP_DECODER_EVENT_DUPLICATE_FIELDS);
1058  return 0;
1059  }
1060  return SMTPParseCommandWithParam(state, line, 4, &state->helo, &state->helo_len);
1061 }
1062 
1063 static int SMTPParseCommandMAILFROM(SMTPState *state, const SMTPLine *line)
1064 {
1065  if (state->curr_tx->mail_from) {
1066  SMTPSetEvent(state, SMTP_DECODER_EVENT_DUPLICATE_FIELDS);
1067  return 0;
1068  }
1069  return SMTPParseCommandWithParam(
1070  state, line, 9, &state->curr_tx->mail_from, &state->curr_tx->mail_from_len);
1071 }
1072 
1073 static int SMTPParseCommandRCPTTO(SMTPState *state, const SMTPLine *line)
1074 {
1075  uint8_t *rcptto;
1076  uint16_t rcptto_len;
1077 
1078  if (SMTPParseCommandWithParam(state, line, 7, &rcptto, &rcptto_len) == 0) {
1079  SMTPString *rcptto_str = SMTPStringAlloc();
1080  if (rcptto_str) {
1081  rcptto_str->str = rcptto;
1082  rcptto_str->len = rcptto_len;
1083  TAILQ_INSERT_TAIL(&state->curr_tx->rcpt_to_list, rcptto_str, next);
1084  } else {
1085  SCFree(rcptto);
1086  return -1;
1087  }
1088  } else {
1089  return -1;
1090  }
1091  return 0;
1092 }
1093 
1094 /* consider 'rset' and 'quit' to be part of the existing state */
1095 static int NoNewTx(SMTPState *state, const SMTPLine *line)
1096 {
1098  if (line->len >= 4 && SCMemcmpLowercase("rset", line->buf, 4) == 0) {
1099  return 1;
1100  } else if (line->len >= 4 && SCMemcmpLowercase("quit", line->buf, 4) == 0) {
1101  return 1;
1102  }
1103  }
1104  return 0;
1105 }
1106 
1107 /* XXX have a better name */
1108 #define rawmsgname "rawmsg"
1110 /*
1111  * @brief Process an SMTP Request
1112  *
1113  * Parse and decide the current command and set appropriate variables on the state
1114  * accordingly. Create transactions if needed or update the current transaction
1115  * with the appropriate data/params. Pass the control to the respective command
1116  * parser in the end.
1117  *
1118  * @param state Pointer to current SMTPState
1119  * @param f Pointer to the current Flow
1120  * @param pstate Pointer to the current AppLayerParserState
1121  * @param input Pointer to the current input data to SMTP parser
1122  * @param line Pointer to the current line being parsed by the SMTP parser
1123  * @return 0 for success
1124  * -1 for errors and inconsistent states
1125  * -2 if MIME state could not be allocated
1126  * */
1127 static int SMTPProcessRequest(
1128  SMTPState *state, Flow *f, SMTPInput *input, const SMTPLine *line, const StreamSlice *slice)
1129 {
1130  SCEnter();
1131  SMTPTransaction *tx = state->curr_tx;
1132 
1134  if (frame) {
1135  frame->len = (int64_t)line->len;
1136  } else {
1137  if (!(state->current_command == SMTP_COMMAND_DATA &&
1139  frame = AppLayerFrameNewByPointer(
1140  f, slice, line->buf, line->len, 0, SMTP_FRAME_COMMAND_LINE);
1141  }
1142  }
1143 
1144  /* If current input is to be discarded because it completes a long line,
1145  * line's length and delimiter len are reset to 0. Skip processing this line.
1146  * This line is only to get us out of the state where we should discard any
1147  * data till LF. */
1148  if (line->len == 0 && line->delim_len == 0) {
1149  return 0;
1150  }
1151  if (state->curr_tx == NULL || (state->curr_tx->done && !NoNewTx(state, line))) {
1152  tx = SMTPTransactionCreate(state);
1153  if (tx == NULL)
1154  return -1;
1155  state->curr_tx = tx;
1156  TAILQ_INSERT_TAIL(&state->tx_list, tx, next);
1157  tx->tx_id = state->tx_cnt++;
1158 
1159  /* keep track of the start of the tx */
1161  StreamTcpReassemblySetMinInspectDepth(f->protoctx, STREAM_TOSERVER,
1163  }
1164  if (frame != NULL && state->curr_tx) {
1165  AppLayerFrameSetTxId(frame, state->curr_tx->tx_id);
1166  }
1167 
1168  state->toserver_data_count += (line->len + line->delim_len);
1169 
1171  SMTPSetEvent(state, SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE);
1172  }
1173 
1174  /* there are 2 commands that can push it into this COMMAND_DATA mode -
1175  * STARTTLS and DATA */
1177  int r = 0;
1178 
1179  if (line->len >= 8 && SCMemcmpLowercase("starttls", line->buf, 8) == 0) {
1181  } else if (line->len >= 4 && SCMemcmpLowercase("data", line->buf, 4) == 0) {
1183  if (state->curr_tx->is_data) {
1184  // We did not receive a confirmation from server
1185  // And now client sends a next DATA
1186  SMTPSetEvent(state, SMTP_DECODER_EVENT_UNPARSABLE_CONTENT);
1187  SCReturnInt(0);
1188  } else if (smtp_config.raw_extraction) {
1190  (uint8_t *)rawmsgname, strlen(rawmsgname), NULL, 0,
1191  FILE_NOMD5 | FILE_NOMAGIC) == 0) {
1192  SMTPNewFile(tx, tx->files_ts.tail);
1193  }
1194  } else if (smtp_config.decode_mime) {
1196  tx->mime_state = SCMimeSmtpStateInit(&tx->files_ts, &smtp_config.sbcfg);
1197  if (tx->mime_state == NULL) {
1198  SCLogDebug("MimeDecInitParser() failed to "
1199  "allocate data");
1200  return -1;
1201  }
1202  }
1203  state->curr_tx->is_data = true;
1204 
1205  Frame *data_frame = AppLayerFrameNewByPointer(
1206  f, slice, input->buf + input->consumed, -1, 0, SMTP_FRAME_DATA);
1207  if (data_frame == NULL) {
1208  SCLogDebug("data_frame %p - no data frame set up", data_frame);
1209  } else {
1210  AppLayerFrameSetTxId(data_frame, state->curr_tx->tx_id);
1211  }
1212 
1213  /* Enter immediately data mode without waiting for server reply */
1216  }
1217  } else if (line->len >= 4 && SCMemcmpLowercase("bdat", line->buf, 4) == 0) {
1218  r = SMTPParseCommandBDAT(state, line);
1219  if (r == -1) {
1220  SCReturnInt(-1);
1221  }
1224  } else if (line->len >= 4 && ((SCMemcmpLowercase("helo", line->buf, 4) == 0) ||
1225  SCMemcmpLowercase("ehlo", line->buf, 4) == 0)) {
1226  r = SMTPParseCommandHELO(state, line);
1227  if (r == -1) {
1228  SCReturnInt(-1);
1229  }
1231  } else if (line->len >= 9 && SCMemcmpLowercase("mail from", line->buf, 9) == 0) {
1232  r = SMTPParseCommandMAILFROM(state, line);
1233  if (r == -1) {
1234  SCReturnInt(-1);
1235  }
1237  } else if (line->len >= 7 && SCMemcmpLowercase("rcpt to", line->buf, 7) == 0) {
1238  r = SMTPParseCommandRCPTTO(state, line);
1239  if (r == -1) {
1240  SCReturnInt(-1);
1241  }
1243  } else if (line->len >= 4 && SCMemcmpLowercase("rset", line->buf, 4) == 0) {
1244  // Resets chunk index in case of connection reuse
1245  state->bdat_chunk_idx = 0;
1247  } else {
1249  }
1250 
1251  /* Every command is inserted into a command buffer, to be matched
1252  * against reply(ies) sent by the server */
1253  if (SMTPInsertCommandIntoCommandBuffer(state->current_command, state) == -1) {
1254  SCReturnInt(-1);
1255  }
1256 
1257  SCReturnInt(r);
1258  }
1259 
1260  switch (state->current_command) {
1261  case SMTP_COMMAND_DATA:
1262  return SMTPProcessCommandDATA(state, tx, f, line);
1263 
1264  case SMTP_COMMAND_BDAT:
1265  return SMTPProcessCommandBDAT(state, line);
1266 
1267  default:
1268  /* we have nothing to do with any other command at this instant.
1269  * Just let it go through */
1270  SCReturnInt(0);
1271  }
1272 }
1273 
1274 static inline void ResetLine(SMTPLine *line)
1275 {
1276  if (line != NULL) {
1277  line->len = 0;
1278  line->delim_len = 0;
1279  line->buf = NULL;
1280  }
1281 }
1282 
1283 /*
1284  * @brief Pre Process the data that comes in DATA mode.
1285  *
1286  * If currently, the command that is being processed is DATA, whatever data
1287  * comes as a part of it must be handled by this function. This is because
1288  * there should be no char limit imposition on the line arriving in the DATA
1289  * mode. Such limits are in place for any lines passed to the GetLine function
1290  * and the lines are capped there at SMTP_LINE_BUFFER_LIMIT.
1291  * One such limit in DATA mode may lead to file data or parts of e-mail being
1292  * truncated if the line were too long.
1293  *
1294  * @param state Pointer to the current SMTPState
1295  * @param f Pointer to the current Flow
1296  * @param pstate Pointer to the current AppLayerParserState
1297  * @param input Pointer to the current input data to SMTP parser
1298  * @param line Pointer to the current line being parsed by the SMTP parser
1299  * @return 0 for success
1300  * 1 for handing control over to GetLine
1301  * -1 for errors and inconsistent states
1302  * */
1303 static int SMTPPreProcessCommands(
1304  SMTPState *state, Flow *f, StreamSlice *slice, SMTPInput *input, SMTPLine *line)
1305 {
1307  DEBUG_VALIDATE_BUG_ON(line->len != 0);
1308  DEBUG_VALIDATE_BUG_ON(line->delim_len != 0);
1309 
1310  /* fall back to strict line parsing for mime header parsing */
1311  if (state->curr_tx && state->curr_tx->mime_state &&
1312  SCMimeSmtpGetState(state->curr_tx->mime_state) < MimeSmtpBody)
1313  return 1;
1314 
1315  bool line_complete = false;
1316  const int32_t input_len = input->len;
1317  const int32_t offset = input->consumed;
1318  for (int32_t i = 0; i < input_len; i++) {
1319  if (input->buf[offset + i] == 0x0d) {
1320  if (i < input_len - 1 && input->buf[offset + i + 1] == 0x0a) {
1321  i++;
1322  line->delim_len++;
1323  }
1324  /* Line is just ending in CR */
1325  line->delim_len++;
1326  line_complete = true;
1327  } else if (input->buf[offset + i] == 0x0a) {
1328  /* Line is just ending in LF */
1329  line->delim_len++;
1330  line_complete = true;
1331  }
1332  /* Either line is complete or fragmented */
1333  if (line_complete || (i == input_len - 1)) {
1334  DEBUG_VALIDATE_BUG_ON(input->consumed + input->len != input->orig_len);
1335  DEBUG_VALIDATE_BUG_ON(input->len == 0 && input_len != 0);
1336  /* state->input_len reflects data from start of the line in progress. */
1337  if ((input->len == 1 && input->buf[input->consumed] == '-') ||
1338  (input->len > 1 && input->buf[input->consumed] == '-' &&
1339  input->buf[input->consumed + 1] == '-')) {
1340  SCLogDebug("Possible boundary, yield to GetLine");
1341  return 1;
1342  }
1343  /* total_consumed should be input consumed so far + i + 1 */
1344  int32_t total_consumed = offset + i + 1;
1345  int32_t current_line_consumed = total_consumed - input->consumed;
1346  DEBUG_VALIDATE_BUG_ON(current_line_consumed < line->delim_len);
1347  line->buf = input->buf + input->consumed;
1348  line->len = current_line_consumed - line->delim_len;
1349  DEBUG_VALIDATE_BUG_ON(line->len < 0);
1350  if (line->len < 0) {
1351  return -1;
1352  }
1353 
1354  input->consumed = total_consumed;
1355  input->len -= current_line_consumed;
1356  DEBUG_VALIDATE_BUG_ON(input->consumed + input->len != input->orig_len);
1357  if (SMTPProcessRequest(state, f, input, line, slice) == -1) {
1358  return -1;
1359  }
1360  line_complete = false;
1361  line->buf = NULL;
1362  line->len = 0;
1363  line->delim_len = 0;
1364 
1365  /* bail if `SMTPProcessRequest` ended the data mode */
1366  if ((state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE) == 0) {
1368  if (data_frame) {
1369  data_frame->len = (slice->offset + input->consumed) - data_frame->offset;
1370  }
1371  break;
1372  }
1373  }
1374  }
1375  return 0;
1376 }
1377 
1378 static AppLayerResult SMTPParse(uint8_t direction, Flow *f, SMTPState *state,
1379  AppLayerParserState *pstate, StreamSlice stream_slice, SMTPThreadCtx *thread_data)
1380 {
1381  SCEnter();
1382 
1383  const uint8_t *input_buf = StreamSliceGetData(&stream_slice);
1384  uint32_t input_len = StreamSliceGetDataLen(&stream_slice);
1385 
1386  if (input_buf == NULL &&
1387  ((direction == 0 && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TS)) ||
1388  (direction == 1 &&
1391  } else if (input_buf == NULL || input_len == 0) {
1393  }
1394 
1395  SMTPInput input = { .buf = input_buf, .len = input_len, .orig_len = input_len, .consumed = 0 };
1396  SMTPLine line = { NULL, 0, 0, false };
1397 
1398  /* toserver */
1399  if (direction == 0) {
1400  if (((state->current_command == SMTP_COMMAND_DATA) ||
1401  (state->current_command == SMTP_COMMAND_BDAT)) &&
1403  int ret = SMTPPreProcessCommands(state, f, &stream_slice, &input, &line);
1404  DEBUG_VALIDATE_BUG_ON(ret != 0 && ret != -1 && ret != 1);
1405  if (ret == 0 && input.consumed == input.orig_len) {
1407  } else if (ret < 0) {
1409  }
1410  }
1411  AppLayerResult res = SMTPGetLine(f, &stream_slice, state, &input, &line, direction);
1412  while (res.status == 0) {
1413  int retval = SMTPProcessRequest(state, f, &input, &line, &stream_slice);
1414  if (retval != 0)
1416  if (line.delim_len == 0 && line.len == SMTP_LINE_BUFFER_LIMIT) {
1417  if (!line.lf_found) {
1418  state->discard_till_lf_ts = true;
1419  }
1420  input.consumed = input.len + 1; // For the newly found LF
1421  SMTPSetEvent(state, SMTP_DECODER_EVENT_TRUNCATED_LINE);
1422  break;
1423  }
1424  /* If request was successfully parsed, reset line as it has already been used
1425  * wherever it had to be */
1426  ResetLine(&line);
1427 
1428  /* If DATA mode was entered in the middle of input parsing, exempt it from GetLine as we
1429  * don't want input limits to be exercised on DATA data. Here, SMTPPreProcessCommands
1430  * should either consume all the data or return in case it encounters another boundary.
1431  * In case of another boundary, the control should be passed to SMTPGetLine */
1432  if ((input.len > 0) && (state->current_command == SMTP_COMMAND_DATA) &&
1434  int ret = SMTPPreProcessCommands(state, f, &stream_slice, &input, &line);
1435  DEBUG_VALIDATE_BUG_ON(ret != 0 && ret != -1 && ret != 1);
1436  if (ret == 0 && input.consumed == input.orig_len) {
1438  } else if (ret < 0) {
1440  }
1441  }
1442  res = SMTPGetLine(f, &stream_slice, state, &input, &line, direction);
1443  }
1444  if (res.status == 1)
1445  return res;
1446  /* toclient */
1447  } else {
1448  AppLayerResult res = SMTPGetLine(f, &stream_slice, state, &input, &line, direction);
1449  while (res.status == 0) {
1450  if (SMTPProcessReply(state, f, thread_data, &input, &line) != 0)
1452  if (line.delim_len == 0 && line.len == SMTP_LINE_BUFFER_LIMIT) {
1453  if (!line.lf_found) {
1454  state->discard_till_lf_tc = true;
1455  }
1456  input.consumed = input.len + 1; // For the newly found LF
1457  SMTPSetEvent(state, SMTP_DECODER_EVENT_TRUNCATED_LINE);
1458  break;
1459  }
1460  res = SMTPGetLine(f, &stream_slice, state, &input, &line, direction);
1461  }
1462  if (res.status == 1)
1463  return res;
1464  }
1465 
1467 }
1468 
1469 static AppLayerResult SMTPParseClientRecord(Flow *f, void *alstate, AppLayerParserState *pstate,
1470  StreamSlice stream_slice, void *local_data)
1471 {
1472  SCEnter();
1473 
1474  /* first arg 0 is toserver */
1475  return SMTPParse(0, f, alstate, pstate, stream_slice, local_data);
1476 }
1477 
1478 static AppLayerResult SMTPParseServerRecord(Flow *f, void *alstate, AppLayerParserState *pstate,
1479  StreamSlice stream_slice, void *local_data)
1480 {
1481  SCEnter();
1482 
1483  /* first arg 1 is toclient */
1484  return SMTPParse(1, f, alstate, pstate, stream_slice, local_data);
1485 }
1486 
1487 /**
1488  * \internal
1489  * \brief Function to allocate SMTP state memory.
1490  */
1491 void *SMTPStateAlloc(void *orig_state, AppProto proto_orig)
1492 {
1493  SMTPState *smtp_state = SCCalloc(1, sizeof(SMTPState));
1494  if (unlikely(smtp_state == NULL))
1495  return NULL;
1496 
1497  smtp_state->cmds = SCMalloc(sizeof(uint8_t) *
1499  if (smtp_state->cmds == NULL) {
1500  SCFree(smtp_state);
1501  return NULL;
1502  }
1504 
1505  TAILQ_INIT(&smtp_state->tx_list);
1506 
1507  return smtp_state;
1508 }
1509 
1510 static SMTPString *SMTPStringAlloc(void)
1511 {
1512  SMTPString *smtp_string = SCCalloc(1, sizeof(SMTPString));
1513  if (unlikely(smtp_string == NULL))
1514  return NULL;
1515 
1516  return smtp_string;
1517 }
1518 
1519 
1520 static void SMTPStringFree(SMTPString *str)
1521 {
1522  if (str->str) {
1523  SCFree(str->str);
1524  }
1525  SCFree(str);
1526 }
1527 
1528 static void *SMTPLocalStorageAlloc(void)
1529 {
1530  /* needed by the mpm */
1531  SMTPThreadCtx *td = SCCalloc(1, sizeof(*td));
1532  if (td == NULL) {
1533  exit(EXIT_FAILURE);
1534  }
1535 
1536  td->pmq = SCCalloc(1, sizeof(*td->pmq));
1537  if (td->pmq == NULL) {
1538  exit(EXIT_FAILURE);
1539  }
1540  PmqSetup(td->pmq);
1541 
1542  td->smtp_mpm_thread_ctx = SCCalloc(1, sizeof(MpmThreadCtx));
1543  if (unlikely(td->smtp_mpm_thread_ctx == NULL)) {
1544  exit(EXIT_FAILURE);
1545  }
1547  return td;
1548 }
1549 
1550 static void SMTPLocalStorageFree(void *ptr)
1551 {
1552  SMTPThreadCtx *td = ptr;
1553  if (td != NULL) {
1554  if (td->pmq != NULL) {
1555  PmqFree(td->pmq);
1556  SCFree(td->pmq);
1557  }
1558 
1559  if (td->smtp_mpm_thread_ctx != NULL) {
1562  }
1563 
1564  SCFree(td);
1565  }
1566 }
1567 
1568 static void SMTPTransactionFree(SMTPTransaction *tx, SMTPState *state)
1569 {
1570  if (tx->mime_state != NULL) {
1571  SCMimeSmtpStateFree(tx->mime_state);
1572  }
1573 
1574  if (tx->tx_data.events != NULL)
1576 
1577  if (tx->tx_data.de_state != NULL)
1578  DetectEngineStateFree(tx->tx_data.de_state);
1579 
1580  if (tx->mail_from)
1581  SCFree(tx->mail_from);
1582 
1583  SMTPString *str = NULL;
1584  while ((str = TAILQ_FIRST(&tx->rcpt_to_list))) {
1585  TAILQ_REMOVE(&tx->rcpt_to_list, str, next);
1586  SMTPStringFree(str);
1587  }
1589 
1590  SCFree(tx);
1591 }
1592 
1593 /**
1594  * \internal
1595  * \brief Function to free SMTP state memory.
1596  */
1597 static void SMTPStateFree(void *p)
1598 {
1599  SMTPState *smtp_state = (SMTPState *)p;
1600 
1601  if (smtp_state->cmds != NULL) {
1602  SCFree(smtp_state->cmds);
1603  }
1604 
1605  if (smtp_state->helo) {
1606  SCFree(smtp_state->helo);
1607  }
1608 
1609  SMTPTransaction *tx = NULL;
1610  while ((tx = TAILQ_FIRST(&smtp_state->tx_list))) {
1611  TAILQ_REMOVE(&smtp_state->tx_list, tx, next);
1612  SMTPTransactionFree(tx, smtp_state);
1613  }
1614 
1615  SCFree(smtp_state);
1616 }
1617 
1618 static void SMTPSetMpmState(void)
1619 {
1620  smtp_mpm_ctx = SCCalloc(1, sizeof(MpmCtx));
1621  if (unlikely(smtp_mpm_ctx == NULL)) {
1622  exit(EXIT_FAILURE);
1623  }
1624  MpmInitCtx(smtp_mpm_ctx, SMTP_MPM);
1625 
1626  uint32_t i = 0;
1627  for (i = 0; i < sizeof(smtp_reply_map)/sizeof(SCEnumCharMap) - 1; i++) {
1628  SCEnumCharMap *map = &smtp_reply_map[i];
1629  /* The third argument is 3, because reply code is always 3 bytes. */
1630  MpmAddPatternCI(smtp_mpm_ctx, (uint8_t *)map->enum_name, 3,
1631  0 /* defunct */, 0 /* defunct */,
1632  i /* pattern id */, i /* rule id */ , 0 /* no flags */);
1633  }
1634 
1635  mpm_table[SMTP_MPM].Prepare(smtp_mpm_ctx);
1636 }
1637 
1638 static void SMTPFreeMpmState(void)
1639 {
1640  if (smtp_mpm_ctx != NULL) {
1641  mpm_table[SMTP_MPM].DestroyCtx(smtp_mpm_ctx);
1642  SCFree(smtp_mpm_ctx);
1643  smtp_mpm_ctx = NULL;
1644  }
1645 }
1646 
1647 static int SMTPStateGetEventInfo(
1648  const char *event_name, uint8_t *event_id, AppLayerEventType *event_type)
1649 {
1650  if (SCAppLayerGetEventIdByName(event_name, smtp_decoder_event_table, event_id) == 0) {
1651  *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
1652  return 0;
1653  }
1654  return -1;
1655 }
1656 
1657 static int SMTPStateGetEventInfoById(
1658  uint8_t event_id, const char **event_name, AppLayerEventType *event_type)
1659 {
1660  *event_name = SCMapEnumValueToName(event_id, smtp_decoder_event_table);
1661  if (*event_name == NULL) {
1662  SCLogError("event \"%d\" not present in "
1663  "smtp's enum map table.",
1664  event_id);
1665  /* yes this is fatal */
1666  return -1;
1667  }
1668 
1669  *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
1670 
1671  return 0;
1672 }
1673 
1674 static AppProto SMTPServerProbingParser(
1675  Flow *f, uint8_t direction, const uint8_t *input, uint32_t len, uint8_t *rdir)
1676 {
1677  // another check for minimum length
1678  if (len < 5) {
1679  return ALPROTO_UNKNOWN;
1680  }
1681  // begins by 220
1682  if (input[0] != '2' || input[1] != '2' || input[2] != '0') {
1683  return ALPROTO_FAILED;
1684  }
1685  // followed by space or hypen
1686  if (input[3] != ' ' && input[3] != '-') {
1687  return ALPROTO_FAILED;
1688  }
1689  // If client side is SMTP, do not validate domain
1690  // so that server banner can be parsed first.
1691  if (f->alproto_ts == ALPROTO_SMTP) {
1692  if (memchr(input + 4, '\n', len - 4) != NULL) {
1693  return ALPROTO_SMTP;
1694  }
1695  return ALPROTO_UNKNOWN;
1696  }
1698  if (f->todstbytecnt > 4 && f->alproto_ts == ALPROTO_UNKNOWN) {
1699  // Only validates SMTP if client side is unknown
1700  // despite having received bytes.
1701  r = ALPROTO_SMTP;
1702  }
1703  uint32_t offset = SCValidateDomain(input + 4, len - 4);
1704  if (offset == 0) {
1705  return ALPROTO_FAILED;
1706  }
1707  if (r != ALPROTO_UNKNOWN && memchr(input + 4, '\n', len - 4) != NULL) {
1708  return r;
1709  }
1710  // This should not go forever because of engine limiting probing parsers.
1711  return ALPROTO_UNKNOWN;
1712 }
1713 
1714 static int SMTPRegisterPatternsForProtocolDetection(void)
1715 {
1717  "EHLO", 4, 0, STREAM_TOSERVER) < 0)
1718  {
1719  return -1;
1720  }
1722  "HELO", 4, 0, STREAM_TOSERVER) < 0)
1723  {
1724  return -1;
1725  }
1727  "QUIT", 4, 0, STREAM_TOSERVER) < 0)
1728  {
1729  return -1;
1730  }
1732  "tcp", IPPROTO_TCP, "smtp", ALPROTO_SMTP, 0, 5, NULL, SMTPServerProbingParser)) {
1733  // STREAM_TOSERVER means here use 25 as flow destination port
1734  AppLayerProtoDetectPPRegister(IPPROTO_TCP, "25,465", ALPROTO_SMTP, 0, 5, STREAM_TOSERVER,
1735  NULL, SMTPServerProbingParser);
1736  }
1737 
1738  return 0;
1739 }
1740 
1741 static void SMTPStateTransactionFree (void *state, uint64_t tx_id)
1742 {
1743  SMTPState *smtp_state = state;
1744  SMTPTransaction *tx = NULL;
1745  TAILQ_FOREACH(tx, &smtp_state->tx_list, next) {
1746  if (tx_id < tx->tx_id)
1747  break;
1748  else if (tx_id > tx->tx_id)
1749  continue;
1750 
1751  if (tx == smtp_state->curr_tx)
1752  smtp_state->curr_tx = NULL;
1753  TAILQ_REMOVE(&smtp_state->tx_list, tx, next);
1754  SMTPTransactionFree(tx, state);
1755  break;
1756  }
1757 
1758 
1759 }
1760 
1761 /** \retval cnt highest tx id */
1762 static uint64_t SMTPStateGetTxCnt(void *state)
1763 {
1764  uint64_t cnt = 0;
1765  SMTPState *smtp_state = state;
1766  if (smtp_state) {
1767  cnt = smtp_state->tx_cnt;
1768  }
1769  SCLogDebug("returning %"PRIu64, cnt);
1770  return cnt;
1771 }
1772 
1773 static void *SMTPStateGetTx(void *state, uint64_t id)
1774 {
1775  SMTPState *smtp_state = state;
1776  if (smtp_state) {
1777  SMTPTransaction *tx = NULL;
1778 
1779  if (smtp_state->curr_tx == NULL)
1780  return NULL;
1781  if (smtp_state->curr_tx->tx_id == id)
1782  return smtp_state->curr_tx;
1783 
1784  TAILQ_FOREACH(tx, &smtp_state->tx_list, next) {
1785  if (tx->tx_id == id)
1786  return tx;
1787  }
1788  }
1789  return NULL;
1790 }
1791 
1792 static int SMTPStateGetAlstateProgress(void *vtx, uint8_t direction)
1793 {
1794  SMTPTransaction *tx = vtx;
1795  return tx->done;
1796 }
1797 
1798 static AppLayerGetFileState SMTPGetTxFiles(void *txv, uint8_t direction)
1799 {
1800  AppLayerGetFileState files = { .fc = NULL, .cfg = &smtp_config.sbcfg };
1801  SMTPTransaction *tx = (SMTPTransaction *)txv;
1802 
1803  if (direction & STREAM_TOSERVER) {
1804  files.fc = &tx->files_ts;
1805  }
1806  return files;
1807 }
1808 
1809 static AppLayerTxData *SMTPGetTxData(void *vtx)
1810 {
1811  SMTPTransaction *tx = (SMTPTransaction *)vtx;
1812  return &tx->tx_data;
1813 }
1814 
1815 static AppLayerStateData *SMTPGetStateData(void *vstate)
1816 {
1817  SMTPState *state = (SMTPState *)vstate;
1818  return &state->state_data;
1819 }
1820 
1821 /** \brief SMTP tx iterator, specialized for its linked list
1822  *
1823  * \retval txptr or NULL if no more txs in list
1824  */
1825 static AppLayerGetTxIterTuple SMTPGetTxIterator(const uint8_t ipproto, const AppProto alproto,
1826  void *alstate, uint64_t min_tx_id, uint64_t max_tx_id, AppLayerGetTxIterState *state)
1827 {
1828  SMTPState *smtp_state = (SMTPState *)alstate;
1829  AppLayerGetTxIterTuple no_tuple = { NULL, 0, false };
1830  if (smtp_state) {
1831  SMTPTransaction *tx_ptr;
1832  if (state->un.ptr == NULL) {
1833  tx_ptr = TAILQ_FIRST(&smtp_state->tx_list);
1834  } else {
1835  tx_ptr = (SMTPTransaction *)state->un.ptr;
1836  }
1837  if (tx_ptr) {
1838  while (tx_ptr->tx_id < min_tx_id) {
1839  tx_ptr = TAILQ_NEXT(tx_ptr, next);
1840  if (!tx_ptr) {
1841  return no_tuple;
1842  }
1843  }
1844  if (tx_ptr->tx_id >= max_tx_id) {
1845  return no_tuple;
1846  }
1847  state->un.ptr = TAILQ_NEXT(tx_ptr, next);
1848  AppLayerGetTxIterTuple tuple = {
1849  .tx_ptr = tx_ptr,
1850  .tx_id = tx_ptr->tx_id,
1851  .has_next = (state->un.ptr != NULL),
1852  };
1853  return tuple;
1854  }
1855  }
1856  return no_tuple;
1857 }
1858 
1859 /**
1860  * \brief Register the SMTP Protocol parser.
1861  */
1863 {
1864  const char *proto_name = "smtp";
1865 
1866  if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
1868  if (SMTPRegisterPatternsForProtocolDetection() < 0 )
1869  return;
1870  } else {
1871  SCLogInfo("Protocol detection and parser disabled for %s protocol.",
1872  proto_name);
1873  return;
1874  }
1875 
1876  if (AppLayerParserConfParserEnabled("tcp", proto_name)) {
1877  AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateAlloc, SMTPStateFree);
1878 
1879  AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_SMTP, STREAM_TOSERVER,
1880  SMTPParseClientRecord);
1881  AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_SMTP, STREAM_TOCLIENT,
1882  SMTPParseServerRecord);
1883 
1884  AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetEventInfo);
1885  AppLayerParserRegisterGetEventInfoById(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetEventInfoById);
1886 
1887  AppLayerParserRegisterLocalStorageFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPLocalStorageAlloc,
1888  SMTPLocalStorageFree);
1889 
1890  AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateTransactionFree);
1891  AppLayerParserRegisterGetTxFilesFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetTxFiles);
1892  AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetAlstateProgress);
1893  AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTxCnt);
1894  AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTx);
1895  AppLayerParserRegisterGetTxIterator(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetTxIterator);
1896  AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetTxData);
1897  AppLayerParserRegisterStateDataFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetStateData);
1900  IPPROTO_TCP, ALPROTO_SMTP, SMTPGetFrameIdByName, SMTPGetFrameNameById);
1901  } else {
1902  SCLogInfo("Parser disabled for %s protocol. Protocol detection still on.", proto_name);
1903  }
1904 
1905  SMTPSetMpmState();
1906 
1907  SMTPConfigure();
1908 
1909 #ifdef UNITTESTS
1911 #endif
1912 }
1913 
1914 /**
1915  * \brief Free memory allocated for global SMTP parser state.
1916  */
1918 {
1919  SMTPFreeMpmState();
1920 }
1921 
1922 /***************************************Unittests******************************/
1923 
1924 #ifdef UNITTESTS
1925 #include "detect-engine-alert.h"
1926 
1927 static void SMTPTestInitConfig(void)
1928 {
1932 
1934 
1936 }
1937 
1938 /*
1939  * \test Test STARTTLS.
1940  */
1941 static int SMTPParserTest01(void)
1942 {
1943  int result = 0;
1944  Flow f;
1945  int r = 0;
1946 
1947  /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
1948  uint8_t welcome_reply[] = {
1949  0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
1950  0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
1951  0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
1952  0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
1953  0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
1954  0x0d, 0x0a
1955  };
1956  uint32_t welcome_reply_len = sizeof(welcome_reply);
1957 
1958  /* EHLO [192.168.0.158]<CR><LF> */
1959  uint8_t request1[] = {
1960  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x5b, 0x31, 0x39,
1961  0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e,
1962  0x31, 0x35, 0x38, 0x5d, 0x0d, 0x0a
1963  };
1964  uint32_t request1_len = sizeof(request1);
1965  /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
1966  * 250-SIZE 35882577<CR><LF>
1967  * 250-8BITMIME<CR><LF>
1968  * 250-STARTTLS<CR><LF>
1969  * 250 ENHANCEDSTATUSCODES<CR><LF>
1970  */
1971  uint8_t reply1[] = {
1972  0x32, 0x35, 0x30, 0x2d, 0x6d, 0x78, 0x2e, 0x67,
1973  0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
1974  0x6d, 0x20, 0x61, 0x74, 0x20, 0x79, 0x6f, 0x75,
1975  0x72, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
1976  0x65, 0x2c, 0x20, 0x5b, 0x31, 0x31, 0x37, 0x2e,
1977  0x31, 0x39, 0x38, 0x2e, 0x31, 0x31, 0x35, 0x2e,
1978  0x35, 0x30, 0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30,
1979  0x2d, 0x53, 0x49, 0x5a, 0x45, 0x20, 0x33, 0x35,
1980  0x38, 0x38, 0x32, 0x35, 0x37, 0x37, 0x0d, 0x0a,
1981  0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49, 0x54,
1982  0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35,
1983  0x30, 0x2d, 0x53, 0x54, 0x41, 0x52, 0x54, 0x54,
1984  0x4c, 0x53, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20,
1985  0x45, 0x4e, 0x48, 0x41, 0x4e, 0x43, 0x45, 0x44,
1986  0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x43, 0x4f,
1987  0x44, 0x45, 0x53, 0x0d, 0x0a
1988  };
1989  uint32_t reply1_len = sizeof(reply1);
1990 
1991  /* STARTTLS<CR><LF> */
1992  uint8_t request2[] = {
1993  0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
1994  0x0d, 0x0a
1995  };
1996  uint32_t request2_len = sizeof(request2);
1997  /* 220 2.0.0 Ready to start TLS<CR><LF> */
1998  uint8_t reply2[] = {
1999  0x32, 0x32, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
2000  0x30, 0x20, 0x52, 0x65, 0x61, 0x64, 0x79, 0x20,
2001  0x74, 0x6f, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74,
2002  0x20, 0x54, 0x4c, 0x53, 0x0d, 0x0a
2003  };
2004  uint32_t reply2_len = sizeof(reply2);
2005 
2006  TcpSession ssn;
2008 
2009  memset(&f, 0, sizeof(f));
2010  memset(&ssn, 0, sizeof(ssn));
2011 
2012  FLOW_INITIALIZE(&f);
2013  f.protoctx = (void *)&ssn;
2014  f.proto = IPPROTO_TCP;
2015  f.alproto = ALPROTO_SMTP;
2016 
2017  StreamTcpInitConfig(true);
2018  SMTPTestInitConfig();
2019 
2020  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2021  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
2022  if (r != 0) {
2023  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2024  goto end;
2025  }
2026  SMTPState *smtp_state = f.alstate;
2027  if (smtp_state == NULL) {
2028  printf("no smtp state: ");
2029  goto end;
2030  }
2031  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2033  printf("smtp parser in inconsistent state\n");
2034  goto end;
2035  }
2036 
2037  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2038  STREAM_TOSERVER, request1, request1_len);
2039  if (r != 0) {
2040  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2041  goto end;
2042  }
2043  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2044  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2046  printf("smtp parser in inconsistent state\n");
2047  goto end;
2048  }
2049 
2050  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2051  STREAM_TOCLIENT, reply1, reply1_len);
2052  if (r != 0) {
2053  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2054  goto end;
2055  }
2056  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2058  printf("smtp parser in inconsistent state\n");
2059  goto end;
2060  }
2061 
2062  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2063  STREAM_TOSERVER, request2, request2_len);
2064  if (r != 0) {
2065  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2066  goto end;
2067  }
2068  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2069  smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS ||
2071  printf("smtp parser in inconsistent state\n");
2072  goto end;
2073  }
2074 
2075  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2076  STREAM_TOCLIENT, reply2, reply2_len);
2077  if (r != 0) {
2078  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2079  goto end;
2080  }
2081  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2082  smtp_state->parser_state !=
2084  printf("smtp parser in inconsistent state\n");
2085  goto end;
2086  }
2087 
2088  if (!FlowChangeProto(&f)) {
2089  goto end;
2090  }
2091 
2092  result = 1;
2093 end:
2094  if (alp_tctx != NULL)
2096  StreamTcpFreeConfig(true);
2097  FLOW_DESTROY(&f);
2098  return result;
2099 }
2100 
2101 /**
2102  * \test Test multiple DATA commands(full mail transactions).
2103  */
2104 static int SMTPParserTest02(void)
2105 {
2106  int result = 0;
2107  Flow f;
2108  int r = 0;
2109 
2110  /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
2111  uint8_t welcome_reply[] = {
2112  0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
2113  0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
2114  0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
2115  0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
2116  0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
2117  0x0d, 0x0a
2118  };
2119  uint32_t welcome_reply_len = sizeof(welcome_reply);
2120 
2121  /* EHLO boo.com<CR><LF> */
2122  uint8_t request1[] = {
2123  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
2124  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
2125  };
2126  uint32_t request1_len = sizeof(request1);
2127  /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
2128  * 250-SIZE 35882577<CR><LF>
2129  * 250-8BITMIME<CR><LF>
2130  * 250-STARTTLS<CR><LF>
2131  * 250 ENHANCEDSTATUSCODES<CR><LF>
2132  */
2133  uint8_t reply1[] = {
2134  0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
2135  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2136  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2137  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
2138  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
2139  0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
2140  0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
2141  0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
2142  0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
2143  0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
2144  0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
2145  0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
2146  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
2147  0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
2148  0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
2149  };
2150  uint32_t reply1_len = sizeof(reply1);
2151 
2152  /* MAIL FROM:asdff@asdf.com<CR><LF> */
2153  uint8_t request2[] = {
2154  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
2155  0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
2156  0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
2157  0x0d, 0x0a
2158  };
2159  uint32_t request2_len = sizeof(request2);
2160  /* 250 2.1.0 Ok<CR><LF> */
2161  uint8_t reply2[] = {
2162  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2163  0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2164  };
2165  uint32_t reply2_len = sizeof(reply2);
2166 
2167  /* RCPT TO:bimbs@gmail.com<CR><LF> */
2168  uint8_t request3[] = {
2169  0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
2170  0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
2171  0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
2172  0x0a
2173  };
2174  uint32_t request3_len = sizeof(request3);
2175  /* 250 2.1.5 Ok<CR><LF> */
2176  uint8_t reply3[] = {
2177  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2178  0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2179  };
2180  uint32_t reply3_len = sizeof(reply3);
2181 
2182  /* DATA<CR><LF> */
2183  uint8_t request4[] = {
2184  0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
2185  };
2186  uint32_t request4_len = sizeof(request4);
2187  /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
2188  uint8_t reply4[] = {
2189  0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
2190  0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
2191  0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
2192  0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
2193  0x4c, 0x46, 0x3e, 0x0d, 0x0a
2194  };
2195  uint32_t reply4_len = sizeof(reply4);
2196 
2197  /* FROM:asdff@asdf.com<CR><LF> */
2198  uint8_t request5_1[] = {
2199  0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
2200  0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
2201  0x63, 0x6f, 0x6d, 0x0d, 0x0a
2202  };
2203  uint32_t request5_1_len = sizeof(request5_1);
2204  /* TO:bimbs@gmail.com<CR><LF> */
2205  uint8_t request5_2[] = {
2206  0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73,
2207  0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63,
2208  0x6f, 0x6d, 0x0d, 0x0a
2209  };
2210  uint32_t request5_2_len = sizeof(request5_2);
2211  /* <CR><LF> */
2212  uint8_t request5_3[] = {
2213  0x0d, 0x0a
2214  };
2215  uint32_t request5_3_len = sizeof(request5_3);
2216  /* this is test mail1<CR><LF> */
2217  uint8_t request5_4[] = {
2218  0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
2219  0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x69,
2220  0x6c, 0x31, 0x0d, 0x0a
2221  };
2222  uint32_t request5_4_len = sizeof(request5_4);
2223  /* .<CR><LF> */
2224  uint8_t request5_5[] = {
2225  0x2e, 0x0d, 0x0a
2226  };
2227  uint32_t request5_5_len = sizeof(request5_5);
2228  /* 250 2.0.0 Ok: queued as 6A1AF20BF2<CR><LF> */
2229  uint8_t reply5[] = {
2230  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
2231  0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
2232  0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
2233  0x36, 0x41, 0x31, 0x41, 0x46, 0x32, 0x30, 0x42,
2234  0x46, 0x32, 0x0d, 0x0a
2235  };
2236  uint32_t reply5_len = sizeof(reply5);
2237 
2238  /* MAIL FROM:asdfg@asdf.com<CR><LF> */
2239  uint8_t request6[] = {
2240  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
2241  0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x67, 0x40,
2242  0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
2243  0x0d, 0x0a
2244  };
2245  uint32_t request6_len = sizeof(request6);
2246  /* 250 2.1.0 Ok<CR><LF> */
2247  uint8_t reply6[] = {
2248  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2249  0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2250  };
2251  uint32_t reply6_len = sizeof(reply6);
2252 
2253  /* RCPT TO:bimbs@gmail.com<CR><LF> */
2254  uint8_t request7[] = {
2255  0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
2256  0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
2257  0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
2258  0x0a
2259  };
2260  uint32_t request7_len = sizeof(request7);
2261  /* 250 2.1.5 Ok<CR><LF> */
2262  uint8_t reply7[] = {
2263  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2264  0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2265  };
2266  uint32_t reply7_len = sizeof(reply7);
2267 
2268  /* DATA<CR><LF> */
2269  uint8_t request8[] = {
2270  0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
2271  };
2272  uint32_t request8_len = sizeof(request8);
2273  /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
2274  uint8_t reply8[] = {
2275  0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
2276  0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
2277  0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
2278  0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
2279  0x4c, 0x46, 0x3e, 0x0d, 0x0a
2280  };
2281  uint32_t reply8_len = sizeof(reply8);
2282 
2283  /* FROM:asdfg@gmail.com<CR><LF> */
2284  uint8_t request9_1[] = {
2285  0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
2286  0x66, 0x67, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c,
2287  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
2288  };
2289  uint32_t request9_1_len = sizeof(request9_1);
2290  /* TO:bimbs@gmail.com<CR><LF> */
2291  uint8_t request9_2[] = {
2292  0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73,
2293  0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63,
2294  0x6f, 0x6d, 0x0d, 0x0a
2295  };
2296  uint32_t request9_2_len = sizeof(request9_2);
2297  /* <CR><LF> */
2298  uint8_t request9_3[] = {
2299  0x0d, 0x0a
2300  };
2301  uint32_t request9_3_len = sizeof(request9_3);
2302  /* this is test mail2<CR><LF> */
2303  uint8_t request9_4[] = {
2304  0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
2305  0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x69,
2306  0x6c, 0x32, 0x0d, 0x0a
2307  };
2308  uint32_t request9_4_len = sizeof(request9_4);
2309  /* .<CR><LF> */
2310  uint8_t request9_5[] = {
2311  0x2e, 0x0d, 0x0a
2312  };
2313  uint32_t request9_5_len = sizeof(request9_5);
2314  /* 250 2.0.0 Ok: queued as 28CFF20BF2<CR><LF> */
2315  uint8_t reply9[] = {
2316  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
2317  0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
2318  0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
2319  0x32, 0x38, 0x43, 0x46, 0x46, 0x32, 0x30, 0x42,
2320  0x46, 0x32, 0x0d, 0x0a
2321  };
2322  uint32_t reply9_len = sizeof(reply9);
2323 
2324  /* QUIT<CR><LF> */
2325  uint8_t request10[] = {
2326  0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
2327  };
2328  uint32_t request10_len = sizeof(request10);
2329  /* 221 2.0.0 Bye<CR><LF> */
2330  uint8_t reply10[] = {
2331  0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
2332  0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
2333  };
2334  uint32_t reply10_len = sizeof(reply10);
2335 
2336  TcpSession ssn;
2338 
2339  memset(&f, 0, sizeof(f));
2340  memset(&ssn, 0, sizeof(ssn));
2341 
2342  FLOW_INITIALIZE(&f);
2343  f.protoctx = (void *)&ssn;
2344  f.proto = IPPROTO_TCP;
2345  f.alproto = ALPROTO_SMTP;
2346 
2347  StreamTcpInitConfig(true);
2348  SMTPTestInitConfig();
2349 
2350  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2351  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
2352  if (r != 0) {
2353  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2354  goto end;
2355  }
2356  SMTPState *smtp_state = f.alstate;
2357  if (smtp_state == NULL) {
2358  printf("no smtp state: ");
2359  goto end;
2360  }
2361  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2363  printf("smtp parser in inconsistent state\n");
2364  goto end;
2365  }
2366 
2367  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2368  STREAM_TOSERVER, request1, request1_len);
2369  if (r != 0) {
2370  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2371  goto end;
2372  }
2373  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2374  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2376  printf("smtp parser in inconsistent state\n");
2377  goto end;
2378  }
2379 
2380  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2381  STREAM_TOCLIENT, reply1, reply1_len);
2382  if (r != 0) {
2383  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2384  goto end;
2385  }
2386  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2388  printf("smtp parser in inconsistent state\n");
2389  goto end;
2390  }
2391 
2392  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2393  STREAM_TOSERVER, request2, request2_len);
2394  if (r != 0) {
2395  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2396  goto end;
2397  }
2398  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2399  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2401  printf("smtp parser in inconsistent state\n");
2402  goto end;
2403  }
2404 
2405  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2406  STREAM_TOCLIENT, reply2, reply2_len);
2407  if (r != 0) {
2408  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2409  goto end;
2410  }
2411  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2413  printf("smtp parser in inconsistent state\n");
2414  goto end;
2415  }
2416 
2417  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2418  STREAM_TOSERVER, request3, request3_len);
2419  if (r != 0) {
2420  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2421  goto end;
2422  }
2423  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2424  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2426  printf("smtp parser in inconsistent state\n");
2427  goto end;
2428  }
2429 
2430  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2431  STREAM_TOCLIENT, reply3, reply3_len);
2432  if (r != 0) {
2433  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2434  goto end;
2435  }
2436  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2438  printf("smtp parser in inconsistent state\n");
2439  goto end;
2440  }
2441 
2442  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2443  STREAM_TOSERVER, request4, request4_len);
2444  if (r != 0) {
2445  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2446  goto end;
2447  }
2448  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2449  smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
2451  printf("smtp parser in inconsistent state\n");
2452  goto end;
2453  }
2454 
2455  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2456  STREAM_TOCLIENT, reply4, reply4_len);
2457  if (r != 0) {
2458  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2459  goto end;
2460  }
2461  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2462  smtp_state->parser_state !=
2464  printf("smtp parser in inconsistent state\n");
2465  goto end;
2466  }
2467 
2468  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2469  STREAM_TOSERVER, request5_1, request5_1_len);
2470  if (r != 0) {
2471  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2472  goto end;
2473  }
2474  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2475  smtp_state->parser_state !=
2477 
2478  printf("smtp parser in inconsistent state\n");
2479  goto end;
2480  }
2481 
2482  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2483  STREAM_TOSERVER, request5_2, request5_2_len);
2484  if (r != 0) {
2485  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2486  goto end;
2487  }
2488  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2489  smtp_state->parser_state !=
2491 
2492  printf("smtp parser in inconsistent state\n");
2493  goto end;
2494  }
2495 
2496  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2497  STREAM_TOSERVER, request5_3, request5_3_len);
2498  if (r != 0) {
2499  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2500  goto end;
2501  }
2502  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2503  smtp_state->parser_state !=
2505 
2506  printf("smtp parser in inconsistent state\n");
2507  goto end;
2508  }
2509 
2510  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2511  STREAM_TOSERVER, request5_4, request5_4_len);
2512  if (r != 0) {
2513  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2514  goto end;
2515  }
2516  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2517  smtp_state->parser_state !=
2519 
2520  printf("smtp parser in inconsistent state\n");
2521  goto end;
2522  }
2523 
2524  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2525  STREAM_TOSERVER, request5_5, request5_5_len);
2526  if (r != 0) {
2527  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2528  goto end;
2529  }
2530  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2531  smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
2533  printf("smtp parser in inconsistent state\n");
2534  goto end;
2535  }
2536 
2537  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2538  STREAM_TOCLIENT, reply5, reply5_len);
2539  if (r != 0) {
2540  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2541  goto end;
2542  }
2543  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2545  printf("smtp parser in inconsistent state\n");
2546  goto end;
2547  }
2548 
2549  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2550  STREAM_TOSERVER, request6, request6_len);
2551  if (r != 0) {
2552  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2553  goto end;
2554  }
2555  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2556  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2558  printf("smtp parser in inconsistent state\n");
2559  goto end;
2560  }
2561 
2562  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2563  STREAM_TOCLIENT, reply6, reply6_len);
2564  if (r != 0) {
2565  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2566  goto end;
2567  }
2568  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2570  printf("smtp parser in inconsistent state\n");
2571  goto end;
2572  }
2573 
2574  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2575  STREAM_TOSERVER, request7, request7_len);
2576  if (r != 0) {
2577  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2578  goto end;
2579  }
2580  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2581  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2583  printf("smtp parser in inconsistent state\n");
2584  goto end;
2585  }
2586 
2587  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2588  STREAM_TOCLIENT, reply7, reply7_len);
2589  if (r != 0) {
2590  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2591  goto end;
2592  }
2593  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2595  printf("smtp parser in inconsistent state\n");
2596  goto end;
2597  }
2598 
2599  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2600  STREAM_TOSERVER, request8, request8_len);
2601  if (r != 0) {
2602  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2603  goto end;
2604  }
2605  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2606  smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
2608  printf("smtp parser in inconsistent state\n");
2609  goto end;
2610  }
2611 
2612  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2613  STREAM_TOCLIENT, reply8, reply8_len);
2614  if (r != 0) {
2615  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2616  goto end;
2617  }
2618  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2619  smtp_state->parser_state !=
2621  printf("smtp parser in inconsistent state\n");
2622  goto end;
2623  }
2624 
2625  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2626  STREAM_TOSERVER, request9_1, request9_1_len);
2627  if (r != 0) {
2628  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2629  goto end;
2630  }
2631  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2632  smtp_state->parser_state !=
2634 
2635  printf("smtp parser in inconsistent state\n");
2636  goto end;
2637  }
2638 
2639  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2640  STREAM_TOSERVER, request9_2, request9_2_len);
2641  if (r != 0) {
2642  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2643  goto end;
2644  }
2645  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2646  smtp_state->parser_state !=
2648 
2649  printf("smtp parser in inconsistent state\n");
2650  goto end;
2651  }
2652 
2653  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2654  STREAM_TOSERVER, request9_3, request9_3_len);
2655  if (r != 0) {
2656  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2657  goto end;
2658  }
2659  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2660  smtp_state->parser_state !=
2662 
2663  printf("smtp parser in inconsistent state\n");
2664  goto end;
2665  }
2666 
2667  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2668  STREAM_TOSERVER, request9_4, request9_4_len);
2669  if (r != 0) {
2670  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2671  goto end;
2672  }
2673  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2674  smtp_state->parser_state !=
2676 
2677  printf("smtp parser in inconsistent state\n");
2678  goto end;
2679  }
2680 
2681  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2682  STREAM_TOSERVER, request9_5, request9_5_len);
2683  if (r != 0) {
2684  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2685  goto end;
2686  }
2687  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2688  smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
2690  printf("smtp parser in inconsistent state\n");
2691  goto end;
2692  }
2693 
2694  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2695  STREAM_TOCLIENT, reply9, reply9_len);
2696  if (r != 0) {
2697  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2698  goto end;
2699  }
2700  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2702  printf("smtp parser in inconsistent state\n");
2703  goto end;
2704  }
2705 
2706  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2707  STREAM_TOSERVER, request10, request10_len);
2708  if (r != 0) {
2709  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2710  goto end;
2711  }
2712  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2713  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2715  printf("smtp parser in inconsistent state\n");
2716  goto end;
2717  }
2718 
2719  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2720  STREAM_TOCLIENT, reply10, reply10_len);
2721  if (r != 0) {
2722  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2723  goto end;
2724  }
2725  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2727  printf("smtp parser in inconsistent state\n");
2728  goto end;
2729  }
2730 
2731  result = 1;
2732 end:
2733  if (alp_tctx != NULL)
2735  StreamTcpFreeConfig(true);
2736  FLOW_DESTROY(&f);
2737  return result;
2738 }
2739 
2740 /**
2741  * \test Testing parsing pipelined commands.
2742  */
2743 static int SMTPParserTest03(void)
2744 {
2745  int result = 0;
2746  Flow f;
2747  int r = 0;
2748 
2749  /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
2750  uint8_t welcome_reply[] = {
2751  0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
2752  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2753  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2754  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
2755  0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
2756  0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
2757  };
2758  uint32_t welcome_reply_len = sizeof(welcome_reply);
2759 
2760  /* EHLO boo.com<CR><LF> */
2761  uint8_t request1[] = {
2762  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
2763  0x2e, 0x63, 0x6f, 0x6d, 0x0a
2764  };
2765  uint32_t request1_len = sizeof(request1);
2766  /* 250-poona_slack_vm1.localdomain<CR><LF>
2767  * 250-PIPELINING<CR><LF>
2768  * 250-SIZE 10240000<CR><LF>
2769  * 250-VRFY<CR><LF>
2770  * 250-ETRN<CR><LF>
2771  * 250-ENHANCEDSTATUSCODES<CR><LF>
2772  * 250-8BITMIME<CR><LF>
2773  * 250 DSN<CR><LF>
2774  */
2775  uint8_t reply1[] = {
2776  0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
2777  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2778  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2779  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
2780  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
2781  0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
2782  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
2783  0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
2784  0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
2785  0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
2786  0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
2787  0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
2788  0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
2789  0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
2790  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
2791  0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
2792  0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
2793  };
2794  uint32_t reply1_len = sizeof(reply1);
2795 
2796  /* MAIL FROM:pbsf@asdfs.com<CR><LF>
2797  * RCPT TO:pbsf@asdfs.com<CR><LF>
2798  * DATA<CR><LF>
2799  * Immediate data
2800  */
2801  uint8_t request2[] = {
2802  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
2803  0x4d, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
2804  0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
2805  0x0d, 0x0a, 0x52, 0x43, 0x50, 0x54, 0x20, 0x54,
2806  0x4f, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
2807  0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
2808  0x0d, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a,
2809  0x49, 0x6d, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74,
2810  0x65, 0x20, 0x64, 0x61, 0x74, 0x61, 0x0d, 0x0a,
2811  };
2812  uint32_t request2_len = sizeof(request2);
2813  /* 250 2.1.0 Ok<CR><LF>
2814  * 250 2.1.5 Ok<CR><LF>
2815  * 354 End data with <CR><LF>.<CR><LF>|<CR><LF>|
2816  */
2817  uint8_t reply2[] = {
2818  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2819  0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a, 0x32, 0x35,
2820  0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, 0x35, 0x20,
2821  0x4f, 0x6b, 0x0d, 0x0a, 0x33, 0x35, 0x34, 0x20,
2822  0x45, 0x6e, 0x64, 0x20, 0x64, 0x61, 0x74, 0x61,
2823  0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x3c, 0x43,
2824  0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x2e, 0x3c,
2825  0x43, 0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x0d,
2826  0x0a
2827  };
2828  uint32_t reply2_len = sizeof(reply2);
2829 
2830  TcpSession ssn;
2832 
2833  memset(&f, 0, sizeof(f));
2834  memset(&ssn, 0, sizeof(ssn));
2835 
2836  FLOW_INITIALIZE(&f);
2837  f.protoctx = (void *)&ssn;
2838  f.proto = IPPROTO_TCP;
2839  f.alproto = ALPROTO_SMTP;
2840 
2841  StreamTcpInitConfig(true);
2842  SMTPTestInitConfig();
2843 
2844  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2845  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
2846  if (r != 0) {
2847  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2848  goto end;
2849  }
2850  SMTPState *smtp_state = f.alstate;
2851  if (smtp_state == NULL) {
2852  printf("no smtp state: ");
2853  goto end;
2854  }
2855  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2857  printf("smtp parser in inconsistent state\n");
2858  goto end;
2859  }
2860 
2861  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2862  STREAM_TOSERVER, request1, request1_len);
2863  if (r != 0) {
2864  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2865  goto end;
2866  }
2867  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2868  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2870  printf("smtp parser in inconsistent state\n");
2871  goto end;
2872  }
2873 
2874  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2875  STREAM_TOCLIENT, reply1, reply1_len);
2876  if (r != 0) {
2877  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2878  goto end;
2879  }
2880  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2881  smtp_state->parser_state !=
2883  printf("smtp parser in inconsistent state\n");
2884  goto end;
2885  }
2886 
2887  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2888  STREAM_TOSERVER, request2, request2_len);
2889  if (r != 0) {
2890  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2891  goto end;
2892  }
2893  if (smtp_state->cmds_cnt != 3 || smtp_state->cmds_idx != 0 ||
2894  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2895  smtp_state->cmds[1] != SMTP_COMMAND_OTHER_CMD ||
2896  smtp_state->cmds[2] != SMTP_COMMAND_DATA ||
2897  smtp_state->parser_state !=
2900  printf("smtp parser in inconsistent state\n");
2901  goto end;
2902  }
2903 
2904  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2905  STREAM_TOCLIENT, reply2, reply2_len);
2906  if (r != 0) {
2907  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2908  goto end;
2909  }
2910  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2911  smtp_state->parser_state !=
2914  printf("smtp parser in inconsistent state\n");
2915  goto end;
2916  }
2917 
2918  result = 1;
2919 end:
2920  if (alp_tctx != NULL)
2922  StreamTcpFreeConfig(true);
2923  FLOW_DESTROY(&f);
2924  return result;
2925 }
2926 
2927 /*
2928  * \test Test smtp with just <LF> delimiter instead of <CR><LF>.
2929  */
2930 static int SMTPParserTest04(void)
2931 {
2932  int result = 0;
2933  Flow f;
2934  int r = 0;
2935 
2936  /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
2937  uint8_t welcome_reply[] = {
2938  0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
2939  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2940  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2941  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
2942  0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
2943  0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
2944  };
2945  uint32_t welcome_reply_len = sizeof(welcome_reply);
2946 
2947  /* EHLO boo.com<CR><LF> */
2948  uint8_t request1[] = {
2949  0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
2950  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2951  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2952  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
2953  0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
2954  0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
2955  };
2956  uint32_t request1_len = sizeof(request1);
2957 
2958  TcpSession ssn;
2960 
2961  memset(&f, 0, sizeof(f));
2962  memset(&ssn, 0, sizeof(ssn));
2963 
2964  FLOW_INITIALIZE(&f);
2965  f.protoctx = (void *)&ssn;
2966  f.proto = IPPROTO_TCP;
2967  f.alproto = ALPROTO_SMTP;
2968 
2969  StreamTcpInitConfig(true);
2970  SMTPTestInitConfig();
2971 
2972  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2973  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
2974  if (r != 0) {
2975  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2976  goto end;
2977  }
2978  SMTPState *smtp_state = f.alstate;
2979  if (smtp_state == NULL) {
2980  printf("no smtp state: ");
2981  goto end;
2982  }
2983  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2985  printf("smtp parser in inconsistent state\n");
2986  goto end;
2987  }
2988 
2989  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2990  STREAM_TOSERVER, request1, request1_len);
2991  if (r != 0) {
2992  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2993  goto end;
2994  }
2995  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2996  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2998  printf("smtp parser in inconsistent state\n");
2999  goto end;
3000  }
3001 
3002  result = 1;
3003 end:
3004  if (alp_tctx != NULL)
3006  StreamTcpFreeConfig(true);
3007  FLOW_DESTROY(&f);
3008  return result;
3009 }
3010 
3011 /*
3012  * \test Test STARTTLS fail.
3013  */
3014 static int SMTPParserTest05(void)
3015 {
3016  int result = 0;
3017  Flow f;
3018  int r = 0;
3019 
3020  /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
3021  uint8_t welcome_reply[] = {
3022  0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
3023  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3024  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3025  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
3026  0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
3027  0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
3028  };
3029  uint32_t welcome_reply_len = sizeof(welcome_reply);
3030 
3031  /* EHLO boo.com<CR><LF> */
3032  uint8_t request1[] = {
3033  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3034  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
3035  };
3036  uint32_t request1_len = sizeof(request1);
3037  /* 250-poona_slack_vm1.localdomain<CR><LF>
3038  * 250-PIPELINING<CR><LF>
3039  * 250-SIZE 10240000<CR><LF>
3040  * 250-VRFY<CR><LF>
3041  * 250-ETRN<CR><LF>
3042  * 250-ENHANCEDSTATUSCODES<CR><LF>
3043  * 250-8BITMIME<CR><LF>
3044  * 250 DSN<CR><LF>
3045  */
3046  uint8_t reply1[] = {
3047  0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
3048  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3049  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3050  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
3051  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
3052  0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
3053  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
3054  0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
3055  0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3056  0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
3057  0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
3058  0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
3059  0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
3060  0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
3061  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
3062  0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
3063  0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
3064  };
3065  uint32_t reply1_len = sizeof(reply1);
3066 
3067  /* STARTTLS<CR><LF> */
3068  uint8_t request2[] = {
3069  0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
3070  0x0d, 0x0a
3071  };
3072  uint32_t request2_len = sizeof(request2);
3073  /* 502 5.5.2 Error: command not recognized<CR><LF> */
3074  uint8_t reply2[] = {
3075  0x35, 0x30, 0x32, 0x20, 0x35, 0x2e, 0x35, 0x2e,
3076  0x32, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x3a,
3077  0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
3078  0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x63,
3079  0x6f, 0x67, 0x6e, 0x69, 0x7a, 0x65, 0x64, 0x0d,
3080  0x0a
3081  };
3082  uint32_t reply2_len = sizeof(reply2);
3083 
3084  /* QUIT<CR><LF> */
3085  uint8_t request3[] = {
3086  0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
3087 
3088  };
3089  uint32_t request3_len = sizeof(request3);
3090  /* 221 2.0.0 Bye<CR><LF> */
3091  uint8_t reply3[] = {
3092  0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
3093  0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
3094  };
3095  uint32_t reply3_len = sizeof(reply3);
3096 
3097  TcpSession ssn;
3099 
3100  memset(&f, 0, sizeof(f));
3101  memset(&ssn, 0, sizeof(ssn));
3102 
3103  FLOW_INITIALIZE(&f);
3104  f.protoctx = (void *)&ssn;
3105  f.proto = IPPROTO_TCP;
3106  f.alproto = ALPROTO_SMTP;
3107 
3108  StreamTcpInitConfig(true);
3109  SMTPTestInitConfig();
3110 
3111  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3112  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
3113  if (r != 0) {
3114  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3115  goto end;
3116  }
3117  SMTPState *smtp_state = f.alstate;
3118  if (smtp_state == NULL) {
3119  printf("no smtp state: ");
3120  goto end;
3121  }
3122  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3124  printf("smtp parser in inconsistent state\n");
3125  goto end;
3126  }
3127 
3128  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3129  STREAM_TOSERVER, request1, request1_len);
3130  if (r != 0) {
3131  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3132  goto end;
3133  }
3134  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3135  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3137  printf("smtp parser in inconsistent state\n");
3138  goto end;
3139  }
3140 
3141  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3142  STREAM_TOCLIENT, reply1, reply1_len);
3143  if (r != 0) {
3144  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3145  goto end;
3146  }
3147  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3148  smtp_state->parser_state !=
3150  printf("smtp parser in inconsistent state\n");
3151  goto end;
3152  }
3153 
3154  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3155  STREAM_TOSERVER, request2, request2_len);
3156  if (r != 0) {
3157  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3158  goto end;
3159  }
3160  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3161  smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS ||
3162  smtp_state->parser_state !=
3164  printf("smtp parser in inconsistent state\n");
3165  goto end;
3166  }
3167 
3168  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3169  STREAM_TOCLIENT, reply2, reply2_len);
3170  if (r != 0) {
3171  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3172  goto end;
3173  }
3174  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3175  smtp_state->parser_state !=
3177  printf("smtp parser in inconsistent state\n");
3178  goto end;
3179  }
3180 
3181  if ((f.flags & FLOW_NOPAYLOAD_INSPECTION) ||
3183  (((TcpSession *)f.protoctx)->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) ||
3184  (((TcpSession *)f.protoctx)->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
3185  goto end;
3186  }
3187 
3188  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3189  STREAM_TOSERVER, request3, request3_len);
3190  if (r != 0) {
3191  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3192  goto end;
3193  }
3194  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3195  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3196  smtp_state->parser_state !=
3198  printf("smtp parser in inconsistent state\n");
3199  goto end;
3200  }
3201 
3202  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3203  STREAM_TOCLIENT, reply3, reply3_len);
3204  if (r != 0) {
3205  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3206  goto end;
3207  }
3208  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3209  smtp_state->parser_state !=
3211  printf("smtp parser in inconsistent state\n");
3212  goto end;
3213  }
3214 
3215  result = 1;
3216 end:
3217  if (alp_tctx != NULL)
3219  StreamTcpFreeConfig(true);
3220  FLOW_DESTROY(&f);
3221  return result;
3222 }
3223 
3224 /**
3225  * \test Test multiple DATA commands(full mail transactions).
3226  */
3227 static int SMTPParserTest06(void)
3228 {
3229  int result = 0;
3230  Flow f;
3231  int r = 0;
3232 
3233  uint8_t welcome_reply[] = {
3234  0x32, 0x32, 0x30, 0x20, 0x62, 0x61, 0x79, 0x30,
3235  0x2d, 0x6d, 0x63, 0x36, 0x2d, 0x66, 0x31, 0x30,
3236  0x2e, 0x62, 0x61, 0x79, 0x30, 0x2e, 0x68, 0x6f,
3237  0x74, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f,
3238  0x6d, 0x20, 0x53, 0x65, 0x6e, 0x64, 0x69, 0x6e,
3239  0x67, 0x20, 0x75, 0x6e, 0x73, 0x6f, 0x6c, 0x69,
3240  0x63, 0x69, 0x74, 0x65, 0x64, 0x20, 0x63, 0x6f,
3241  0x6d, 0x6d, 0x65, 0x72, 0x63, 0x69, 0x61, 0x6c,
3242  0x20, 0x6f, 0x72, 0x20, 0x62, 0x75, 0x6c, 0x6b,
3243  0x20, 0x65, 0x2d, 0x6d, 0x61, 0x69, 0x6c, 0x20,
3244  0x74, 0x6f, 0x20, 0x4d, 0x69, 0x63, 0x72, 0x6f,
3245  0x73, 0x6f, 0x66, 0x74, 0x27, 0x73, 0x20, 0x63,
3246  0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x20,
3247  0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20,
3248  0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x68, 0x69,
3249  0x62, 0x69, 0x74, 0x65, 0x64, 0x2e, 0x20, 0x4f,
3250  0x74, 0x68, 0x65, 0x72, 0x20, 0x72, 0x65, 0x73,
3251  0x74, 0x72, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e,
3252  0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x66, 0x6f,
3253  0x75, 0x6e, 0x64, 0x20, 0x61, 0x74, 0x20, 0x68,
3254  0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x72,
3255  0x69, 0x76, 0x61, 0x63, 0x79, 0x2e, 0x6d, 0x73,
3256  0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x41, 0x6e,
3257  0x74, 0x69, 0x2d, 0x73, 0x70, 0x61, 0x6d, 0x2f,
3258  0x2e, 0x20, 0x56, 0x69, 0x6f, 0x6c, 0x61, 0x74,
3259  0x69, 0x6f, 0x6e, 0x73, 0x20, 0x77, 0x69, 0x6c,
3260  0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74,
3261  0x20, 0x69, 0x6e, 0x20, 0x75, 0x73, 0x65, 0x20,
3262  0x6f, 0x66, 0x20, 0x65, 0x71, 0x75, 0x69, 0x70,
3263  0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x63,
3264  0x61, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20,
3265  0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e,
3266  0x69, 0x61, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6f,
3267  0x74, 0x68, 0x65, 0x72, 0x20, 0x73, 0x74, 0x61,
3268  0x74, 0x65, 0x73, 0x2e, 0x20, 0x46, 0x72, 0x69,
3269  0x2c, 0x20, 0x31, 0x36, 0x20, 0x46, 0x65, 0x62,
3270  0x20, 0x32, 0x30, 0x30, 0x37, 0x20, 0x30, 0x35,
3271  0x3a, 0x30, 0x33, 0x3a, 0x32, 0x33, 0x20, 0x2d,
3272  0x30, 0x38, 0x30, 0x30, 0x20, 0x0d, 0x0a
3273  };
3274  uint32_t welcome_reply_len = sizeof(welcome_reply);
3275 
3276  uint8_t request1[] = {
3277  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x45, 0x58, 0x43,
3278  0x48, 0x41, 0x4e, 0x47, 0x45, 0x32, 0x2e, 0x63,
3279  0x67, 0x63, 0x65, 0x6e, 0x74, 0x2e, 0x6d, 0x69,
3280  0x61, 0x6d, 0x69, 0x2e, 0x65, 0x64, 0x75, 0x0d,
3281  0x0a
3282  };
3283  uint32_t request1_len = sizeof(request1);
3284 
3285  uint8_t reply1[] = {
3286  0x32, 0x35, 0x30, 0x2d, 0x62, 0x61, 0x79, 0x30,
3287  0x2d, 0x6d, 0x63, 0x36, 0x2d, 0x66, 0x31, 0x30,
3288  0x2e, 0x62, 0x61, 0x79, 0x30, 0x2e, 0x68, 0x6f,
3289  0x74, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f,
3290  0x6d, 0x20, 0x28, 0x33, 0x2e, 0x33, 0x2e, 0x31,
3291  0x2e, 0x34, 0x29, 0x20, 0x48, 0x65, 0x6c, 0x6c,
3292  0x6f, 0x20, 0x5b, 0x31, 0x32, 0x39, 0x2e, 0x31,
3293  0x37, 0x31, 0x2e, 0x33, 0x32, 0x2e, 0x35, 0x39,
3294  0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53,
3295  0x49, 0x5a, 0x45, 0x20, 0x32, 0x39, 0x36, 0x39,
3296  0x36, 0x30, 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35,
3297  0x30, 0x2d, 0x38, 0x62, 0x69, 0x74, 0x6d, 0x69,
3298  0x6d, 0x65, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3299  0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x4d, 0x49,
3300  0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3301  0x43, 0x48, 0x55, 0x4e, 0x4b, 0x49, 0x4e, 0x47,
3302  0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x41, 0x55,
3303  0x54, 0x48, 0x20, 0x4c, 0x4f, 0x47, 0x49, 0x4e,
3304  0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x41, 0x55,
3305  0x54, 0x48, 0x3d, 0x4c, 0x4f, 0x47, 0x49, 0x4e,
3306  0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20, 0x4f, 0x4b,
3307  0x0d, 0x0a
3308  };
3309  uint32_t reply1_len = sizeof(reply1);
3310 
3311  /* MAIL FROM:asdff@asdf.com<CR><LF> */
3312  uint8_t request2[] = {
3313  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
3314  0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
3315  0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
3316  0x0d, 0x0a
3317  };
3318  uint32_t request2_len = sizeof(request2);
3319  /* 250 2.1.0 Ok<CR><LF> */
3320  uint8_t reply2[] = {
3321  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
3322  0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
3323  };
3324  uint32_t reply2_len = sizeof(reply2);
3325 
3326  /* RCPT TO:bimbs@gmail.com<CR><LF> */
3327  uint8_t request3[] = {
3328  0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
3329  0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
3330  0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
3331  0x0a
3332  };
3333  uint32_t request3_len = sizeof(request3);
3334  /* 250 2.1.5 Ok<CR><LF> */
3335  uint8_t reply3[] = {
3336  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
3337  0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
3338  };
3339  uint32_t reply3_len = sizeof(reply3);
3340 
3341  /* BDAT 51<CR><LF> */
3342  uint8_t request4[] = {
3343  0x42, 0x44, 0x41, 0x54, 0x20, 0x35, 0x31, 0x0d,
3344  0x0a,
3345  };
3346  uint32_t request4_len = sizeof(request4);
3347 
3348  uint8_t request5[] = {
3349  0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
3350  0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
3351  0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
3352  0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x0d, 0x0a,
3353  };
3354  uint32_t request5_len = sizeof(request5);
3355 
3356  uint8_t request6[] = {
3357  0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
3358  0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
3359  0x66, 0x0d, 0x0a,
3360  };
3361  uint32_t request6_len = sizeof(request6);
3362 
3363  TcpSession ssn;
3365 
3366  memset(&f, 0, sizeof(f));
3367  memset(&ssn, 0, sizeof(ssn));
3368 
3369  FLOW_INITIALIZE(&f);
3370  f.protoctx = (void *)&ssn;
3371  f.proto = IPPROTO_TCP;
3372  f.alproto = ALPROTO_SMTP;
3373 
3374  StreamTcpInitConfig(true);
3375  SMTPTestInitConfig();
3376 
3377  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3378  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
3379  if (r != 0) {
3380  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3381  goto end;
3382  }
3383  SMTPState *smtp_state = f.alstate;
3384  if (smtp_state == NULL) {
3385  printf("no smtp state: ");
3386  goto end;
3387  }
3388  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3390  printf("smtp parser in inconsistent state\n");
3391  goto end;
3392  }
3393 
3394  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3395  STREAM_TOSERVER, request1, request1_len);
3396  if (r != 0) {
3397  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3398  goto end;
3399  }
3400  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3401  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3403  printf("smtp parser in inconsistent state\n");
3404  goto end;
3405  }
3406 
3407  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3408  STREAM_TOCLIENT, reply1, reply1_len);
3409  if (r != 0) {
3410  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3411  goto end;
3412  }
3413  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3415  printf("smtp parser in inconsistent state\n");
3416  goto end;
3417  }
3418 
3419  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3420  STREAM_TOSERVER, request2, request2_len);
3421  if (r != 0) {
3422  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3423  goto end;
3424  }
3425  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3426  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3428  printf("smtp parser in inconsistent state\n");
3429  goto end;
3430  }
3431 
3432  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3433  STREAM_TOCLIENT, reply2, reply2_len);
3434  if (r != 0) {
3435  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3436  goto end;
3437  }
3438  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3440  printf("smtp parser in inconsistent state\n");
3441  goto end;
3442  }
3443 
3444  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3445  STREAM_TOSERVER, request3, request3_len);
3446  if (r != 0) {
3447  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3448  goto end;
3449  }
3450  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3451  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3453  printf("smtp parser in inconsistent state\n");
3454  goto end;
3455  }
3456 
3457  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3458  STREAM_TOCLIENT, reply3, reply3_len);
3459  if (r != 0) {
3460  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3461  goto end;
3462  }
3463  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3465  printf("smtp parser in inconsistent state\n");
3466  goto end;
3467  }
3468 
3469  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3470  STREAM_TOSERVER, request4, request4_len);
3471  if (r != 0) {
3472  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3473  goto end;
3474  }
3475  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3476  smtp_state->cmds[0] != SMTP_COMMAND_BDAT ||
3477  smtp_state->parser_state !=
3479  smtp_state->bdat_chunk_len != 51 || smtp_state->bdat_chunk_idx != 0) {
3480  printf("smtp parser in inconsistent state\n");
3481  goto end;
3482  }
3483 
3484  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3485  STREAM_TOSERVER, request5, request5_len);
3486  if (r != 0) {
3487  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3488  goto end;
3489  }
3490  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3491  smtp_state->parser_state !=
3493  smtp_state->bdat_chunk_len != 51 || smtp_state->bdat_chunk_idx != 32) {
3494  printf("smtp parser in inconsistent state\n");
3495  goto end;
3496  }
3497 
3498  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3499  STREAM_TOSERVER, request6, request6_len);
3500  if (r != 0) {
3501  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3502  goto end;
3503  }
3504  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3506  smtp_state->bdat_chunk_len != 51 || smtp_state->bdat_chunk_idx != 51) {
3507  printf("smtp parser in inconsistent state\n");
3508  goto end;
3509  }
3510 
3511  result = 1;
3512 end:
3513  if (alp_tctx != NULL)
3515  StreamTcpFreeConfig(true);
3516  FLOW_DESTROY(&f);
3517  return result;
3518 }
3519 
3520 static int SMTPParserTest12(void)
3521 {
3522  int result = 0;
3523  Signature *s = NULL;
3524  ThreadVars th_v;
3525  Packet *p = NULL;
3526  Flow f;
3527  TcpSession ssn;
3528  DetectEngineThreadCtx *det_ctx = NULL;
3529  DetectEngineCtx *de_ctx = NULL;
3530  SMTPState *smtp_state = NULL;
3531  int r = 0;
3532 
3533  /* EHLO boo.com<CR><LF> */
3534  uint8_t request1[] = {
3535  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3536  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3537  };
3538  int32_t request1_len = sizeof(request1);
3539 
3540  /* 388<CR><LF>
3541  */
3542  uint8_t reply1[] = {
3543  0x31, 0x38, 0x38, 0x0d, 0x0a,
3544  };
3545  uint32_t reply1_len = sizeof(reply1);
3546 
3548 
3549  memset(&th_v, 0, sizeof(th_v));
3550  memset(&f, 0, sizeof(f));
3551  memset(&ssn, 0, sizeof(ssn));
3552 
3553  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
3554 
3555  FLOW_INITIALIZE(&f);
3556  f.protoctx = (void *)&ssn;
3557  f.proto = IPPROTO_TCP;
3558  f.alproto = ALPROTO_SMTP;
3559  p->flow = &f;
3563  f.alproto = ALPROTO_SMTP;
3564 
3565  StreamTcpInitConfig(true);
3566  SMTPTestInitConfig();
3567 
3569  if (de_ctx == NULL)
3570  goto end;
3571 
3572  de_ctx->flags |= DE_QUIET;
3573 
3574  s = DetectEngineAppendSig(de_ctx,"alert tcp any any -> any any "
3575  "(msg:\"SMTP event handling\"; "
3576  "app-layer-event: smtp.invalid_reply; "
3577  "sid:1;)");
3578  if (s == NULL)
3579  goto end;
3580 
3582  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
3583 
3584  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3585  STREAM_TOSERVER | STREAM_START, request1,
3586  request1_len);
3587  if (r != 0) {
3588  printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
3589  goto end;
3590  }
3591 
3592  smtp_state = f.alstate;
3593  if (smtp_state == NULL) {
3594  printf("no smtp state: ");
3595  goto end;
3596  }
3597 
3598  /* do detect */
3599  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3600 
3601  if (PacketAlertCheck(p, 1)) {
3602  printf("sid 1 matched. It shouldn't match: ");
3603  goto end;
3604  }
3605 
3606  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3607  STREAM_TOCLIENT | STREAM_TOCLIENT, reply1,
3608  reply1_len);
3609  if (r == 0) {
3610  printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
3611  goto end;
3612  }
3613 
3614  /* do detect */
3615  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3616 
3617  if (!PacketAlertCheck(p, 1)) {
3618  printf("sid 1 didn't match. Should have matched: ");
3619  goto end;
3620  }
3621 
3622  result = 1;
3623 
3624 end:
3627 
3628  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
3630 
3631  if (alp_tctx != NULL)
3633  StreamTcpFreeConfig(true);
3634  FLOW_DESTROY(&f);
3635  UTHFreePackets(&p, 1);
3636  return result;
3637 }
3638 
3639 static int SMTPParserTest13(void)
3640 {
3641  int result = 0;
3642  Signature *s = NULL;
3643  ThreadVars th_v;
3644  Packet *p = NULL;
3645  Flow f;
3646  TcpSession ssn;
3647  DetectEngineThreadCtx *det_ctx = NULL;
3648  DetectEngineCtx *de_ctx = NULL;
3649  SMTPState *smtp_state = NULL;
3650  int r = 0;
3651 
3652  /* EHLO boo.com<CR><LF> */
3653  uint8_t request1[] = {
3654  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3655  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3656  };
3657  int32_t request1_len = sizeof(request1);
3658 
3659  /* 250<CR><LF>
3660  */
3661  uint8_t reply1[] = {
3662  0x32, 0x35, 0x30, 0x0d, 0x0a,
3663  };
3664  uint32_t reply1_len = sizeof(reply1);
3665 
3666  /* MAIL FROM:pbsf@asdfs.com<CR><LF>
3667  * RCPT TO:pbsf@asdfs.com<CR><LF>
3668  * DATA<CR><LF>
3669  * STARTTLS<CR><LF>
3670  */
3671  uint8_t request2[] = {
3672  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
3673  0x4d, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
3674  0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
3675  0x0d, 0x0a, 0x52, 0x43, 0x50, 0x54, 0x20, 0x54,
3676  0x4f, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
3677  0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
3678  0x0d, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a,
3679  0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
3680  0x0d, 0x0a
3681  };
3682  uint32_t request2_len = sizeof(request2);
3683 
3685 
3686  memset(&th_v, 0, sizeof(th_v));
3687  memset(&f, 0, sizeof(f));
3688  memset(&ssn, 0, sizeof(ssn));
3689 
3690  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
3691 
3692  FLOW_INITIALIZE(&f);
3693  f.protoctx = (void *)&ssn;
3694  f.proto = IPPROTO_TCP;
3695  f.alproto = ALPROTO_SMTP;
3696  p->flow = &f;
3700  f.alproto = ALPROTO_SMTP;
3701 
3702  StreamTcpInitConfig(true);
3703  SMTPTestInitConfig();
3704 
3706  if (de_ctx == NULL)
3707  goto end;
3708 
3709  de_ctx->flags |= DE_QUIET;
3710 
3711  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
3712  "(msg:\"SMTP event handling\"; "
3713  "app-layer-event: "
3714  "smtp.invalid_pipelined_sequence; "
3715  "sid:1;)");
3716  if (s == NULL)
3717  goto end;
3718 
3720  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
3721 
3722  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3723  STREAM_TOSERVER | STREAM_START, request1,
3724  request1_len);
3725  if (r != 0) {
3726  printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
3727  goto end;
3728  }
3729 
3730  smtp_state = f.alstate;
3731  if (smtp_state == NULL) {
3732  printf("no smtp state: ");
3733  goto end;
3734  }
3735 
3736  /* do detect */
3737  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3738 
3739  if (PacketAlertCheck(p, 1)) {
3740  printf("sid 1 matched. It shouldn't match: ");
3741  goto end;
3742  }
3743 
3744  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3745  STREAM_TOCLIENT, reply1, reply1_len);
3746  if (r != 0) {
3747  printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
3748  goto end;
3749  }
3750 
3751  /* do detect */
3752  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3753 
3754  if (PacketAlertCheck(p, 1)) {
3755  printf("sid 1 matched. It shouldn't match: ");
3756  goto end;
3757  }
3758 
3759  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3760  STREAM_TOSERVER, request2, request2_len);
3761  if (r != 0) {
3762  printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
3763  goto end;
3764  }
3765 
3766  /* do detect */
3767  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3768 
3769  if (!PacketAlertCheck(p, 1)) {
3770  printf("sid 1 didn't match. Should have matched: ");
3771  goto end;
3772  }
3773 
3774  result = 1;
3775 
3776 end:
3779 
3780  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
3782 
3783  if (alp_tctx != NULL)
3785  StreamTcpFreeConfig(true);
3786  FLOW_DESTROY(&f);
3787  UTHFreePackets(&p, 1);
3788  return result;
3789 }
3790 
3791 /**
3792  * \test Test DATA command w/MIME message.
3793  */
3794 static int SMTPParserTest14(void)
3795 {
3796  int result = 0;
3797  Flow f;
3798  int r = 0;
3799 
3800  /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
3801  static uint8_t welcome_reply[] = {
3802  0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
3803  0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
3804  0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
3805  0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
3806  0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
3807  0x0d, 0x0a
3808  };
3809  static uint32_t welcome_reply_len = sizeof(welcome_reply);
3810 
3811  /* EHLO boo.com<CR><LF> */
3812  static uint8_t request1[] = {
3813  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3814  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
3815  };
3816  static uint32_t request1_len = sizeof(request1);
3817  /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
3818  * 250-SIZE 35882577<CR><LF>
3819  * 250-8BITMIME<CR><LF>
3820  * 250-STARTTLS<CR><LF>
3821  * 250 ENHANCEDSTATUSCODES<CR><LF>
3822  */
3823  static uint8_t reply1[] = {
3824  0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
3825  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3826  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3827  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
3828  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
3829  0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
3830  0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3831  0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
3832  0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
3833  0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
3834  0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
3835  0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
3836  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
3837  0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
3838  0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
3839  };
3840  static uint32_t reply1_len = sizeof(reply1);
3841 
3842  /* MAIL FROM:asdff@asdf.com<CR><LF> */
3843  static uint8_t request2[] = {
3844  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
3845  0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
3846  0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
3847  0x0d, 0x0a
3848  };
3849  static uint32_t request2_len = sizeof(request2);
3850  /* 250 2.1.0 Ok<CR><LF> */
3851  static uint8_t reply2[] = {
3852  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
3853  0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
3854  };
3855  static uint32_t reply2_len = sizeof(reply2);
3856 
3857  /* RCPT TO:bimbs@gmail.com<CR><LF> */
3858  static uint8_t request3[] = {
3859  0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
3860  0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
3861  0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
3862  0x0a
3863  };
3864  static uint32_t request3_len = sizeof(request3);
3865  /* 250 2.1.5 Ok<CR><LF> */
3866  static uint8_t reply3[] = {
3867  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
3868  0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
3869  };
3870  static uint32_t reply3_len = sizeof(reply3);
3871 
3872  /* DATA<CR><LF> */
3873  static uint8_t request4[] = {
3874  0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
3875  };
3876  static uint32_t request4_len = sizeof(request4);
3877  /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
3878  static uint8_t reply4[] = {
3879  0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
3880  0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
3881  0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
3882  0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
3883  0x4c, 0x46, 0x3e, 0x0d, 0x0a
3884  };
3885  static uint32_t reply4_len = sizeof(reply4);
3886 
3887  /* MIME_MSG */
3888  static uint64_t filesize = 133;
3889  static uint8_t request4_msg[] = {
3890  0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72,
3891  0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E,
3892  0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
3893  0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A,
3894  0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61,
3895  0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74,
3896  0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61,
3897  0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
3898  0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73,
3899  0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F,
3900  0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61,
3901  0x73, 0x65, 0x36, 0x34, 0x0D, 0x0A, 0x43, 0x6F,
3902  0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x44, 0x69,
3903  0x73, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F,
3904  0x6E, 0x3A, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63,
3905  0x68, 0x6D, 0x65, 0x6E, 0x74, 0x3B, 0x20, 0x66,
3906  0x69, 0x6C, 0x65, 0x6E, 0x61, 0x6D, 0x65, 0x3D,
3907  0x22, 0x74, 0x65, 0x73, 0x74, 0x2E, 0x65, 0x78,
3908  0x65, 0x22, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x54,
3909  0x56, 0x6F, 0x41, 0x41, 0x46, 0x42, 0x46, 0x41,
3910  0x41, 0x42, 0x4D, 0x41, 0x51, 0x45, 0x41, 0x61,
3911  0x69, 0x70, 0x59, 0x77, 0x77, 0x41, 0x41, 0x41,
3912  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
3913  0x41, 0x41, 0x44, 0x41, 0x51, 0x73, 0x42, 0x43,
3914  0x41, 0x41, 0x42, 0x41, 0x41, 0x43, 0x41, 0x41,
3915  0x41, 0x41, 0x41, 0x41, 0x48, 0x6B, 0x41, 0x41,
3916  0x41, 0x41, 0x4D, 0x41, 0x41, 0x41, 0x41, 0x65,
3917  0x51, 0x41, 0x41, 0x41, 0x41, 0x77, 0x41, 0x41,
3918  0x41, 0x41, 0x41, 0x41, 0x45, 0x41, 0x41, 0x42,
3919  0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
3920  0x41, 0x42, 0x30, 0x41, 0x41, 0x41, 0x41, 0x49,
3921  0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
3922  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
3923  0x41, 0x45, 0x41, 0x41, 0x49, 0x67, 0x41, 0x41,
3924  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
3925  0x67, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
3926  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
3927  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
3928  0x41, 0x42, 0x63, 0x58, 0x44, 0x59, 0x32, 0x4C,
3929  0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C,
3930  0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F,
3931  0x41, 0x3D, 0x3D, 0x0D,0x0A };
3932  static uint32_t request4_msg_len = sizeof(request4_msg);
3933 
3934  /* DATA COMPLETED */
3935  static uint8_t request4_end[] = {
3936  0x0d, 0x0a, 0x2e, 0x0d, 0x0a
3937  };
3938  static uint32_t request4_end_len = sizeof(request4_end);
3939  /* 250 2.0.0 Ok: queued as 6A1AF20BF2<CR><LF> */
3940  static uint8_t reply4_end[] = {
3941  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
3942  0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
3943  0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
3944  0x36, 0x41, 0x31, 0x41, 0x46, 0x32, 0x30, 0x42,
3945  0x46, 0x32, 0x0d, 0x0a
3946  };
3947  static uint32_t reply4_end_len = sizeof(reply4_end);
3948 
3949  /* QUIT<CR><LF> */
3950  static uint8_t request5[] = {
3951  0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
3952  };
3953  static uint32_t request5_len = sizeof(request5);
3954  /* 221 2.0.0 Bye<CR><LF> */
3955  static uint8_t reply5[] = {
3956  0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
3957  0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
3958  };
3959  static uint32_t reply5_len = sizeof(reply5);
3960 
3961  TcpSession ssn;
3963 
3964  memset(&f, 0, sizeof(f));
3965  memset(&ssn, 0, sizeof(ssn));
3966 
3967  FLOW_INITIALIZE(&f);
3968  f.protoctx = (void *)&ssn;
3969  f.proto = IPPROTO_TCP;
3970  f.alproto = ALPROTO_SMTP;
3971 
3972  StreamTcpInitConfig(true);
3973  SMTPTestInitConfig();
3974 
3975  /* Welcome reply */
3976  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3977  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
3978  if (r != 0) {
3979  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3980  goto end;
3981  }
3982  SMTPState *smtp_state = f.alstate;
3983  if (smtp_state == NULL) {
3984  printf("no smtp state: ");
3985  goto end;
3986  }
3987  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3989  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
3990  goto end;
3991  }
3992 
3993  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3994  STREAM_TOSERVER, request1, request1_len);
3995  if (r != 0) {
3996  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3997  goto end;
3998  }
3999  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
4000  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4002  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4003  goto end;
4004  }
4005 
4006  /* EHLO Reply */
4007  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4008  STREAM_TOCLIENT, reply1, reply1_len);
4009  if (r != 0) {
4010  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4011  goto end;
4012  }
4013 
4014  if ((smtp_state->helo_len != 7) || strncmp("boo.com", (char *)smtp_state->helo, 7)) {
4015  printf("incorrect parsing of HELO field '%s' (%d)\n", smtp_state->helo, smtp_state->helo_len);
4016  goto end;
4017  }
4018 
4019  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
4021  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4022  goto end;
4023  }
4024 
4025  /* MAIL FROM Request */
4026  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4027  STREAM_TOSERVER, request2, request2_len);
4028  if (r != 0) {
4029  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4030  goto end;
4031  }
4032  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
4033  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4035  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4036  goto end;
4037  }
4038 
4039  /* MAIL FROM Reply */
4040  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4041  STREAM_TOCLIENT, reply2, reply2_len);
4042  if (r != 0) {
4043  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4044  goto end;
4045  }
4046 
4047  if ((smtp_state->curr_tx->mail_from_len != 14) ||
4048  strncmp("asdff@asdf.com", (char *)smtp_state->curr_tx->mail_from, 14)) {
4049  printf("incorrect parsing of MAIL FROM field '%s' (%d)\n",
4050  smtp_state->curr_tx->mail_from,
4051  smtp_state->curr_tx->mail_from_len);
4052  goto end;
4053  }
4054 
4055  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
4057  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4058  goto end;
4059  }
4060 
4061  /* RCPT TO Request */
4062  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4063  STREAM_TOSERVER, request3, request3_len);
4064  if (r != 0) {
4065  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4066  goto end;
4067  }
4068  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
4069  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4071  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4072  goto end;
4073  }
4074 
4075  /* RCPT TO Reply */
4076  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4077  STREAM_TOCLIENT, reply3, reply3_len);
4078  if (r != 0) {
4079  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4080  goto end;
4081  }
4082  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
4084  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4085  goto end;
4086  }
4087 
4088  /* Enable mime decoding */
4089  smtp_config.decode_mime = true;
4090  SCMimeSmtpConfigDecodeBase64(1);
4091  SCMimeSmtpConfigDecodeQuoted(1);
4092 
4093  /* DATA request */
4094  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4095  STREAM_TOSERVER, request4, request4_len);
4096  if (r != 0) {
4097  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4098  goto end;
4099  }
4100 
4101  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
4102  smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
4104  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4105  goto end;
4106  }
4107 
4108  /* Data reply */
4109  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4110  STREAM_TOCLIENT, reply4, reply4_len);
4111  if (r != 0) {
4112  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4113  goto end;
4114  }
4115  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
4116  smtp_state->parser_state !=
4118  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4119  goto end;
4120  }
4121 
4122  /* DATA message */
4123  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4124  STREAM_TOSERVER, request4_msg, request4_msg_len);
4125  if (r != 0) {
4126  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4127  goto end;
4128  }
4129 
4130  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
4131  smtp_state->curr_tx->mime_state == NULL ||
4132  smtp_state->parser_state !=
4134  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4135  goto end;
4136  }
4137 
4138  /* DATA . request */
4139  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4140  STREAM_TOSERVER, request4_end, request4_end_len);
4141  if (r != 0) {
4142  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4143  goto end;
4144  }
4145 
4146  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
4147  smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
4148  smtp_state->curr_tx->mime_state == NULL ||
4150  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4151  goto end;
4152  }
4153 
4154  SMTPState *state = (SMTPState *) f.alstate;
4155  FAIL_IF_NULL(state);
4156  FAIL_IF_NULL(state->curr_tx);
4157 
4158  FileContainer *files = &state->curr_tx->files_ts;
4159  if (files != NULL && files->head != NULL) {
4160  File *file = files->head;
4161 
4162  if(strncmp((const char *)file->name, "test.exe", 8) != 0){
4163  printf("smtp-mime file name is incorrect");
4164  goto end;
4165  }
4166  if (FileTrackedSize(file) != filesize){
4167  printf("smtp-mime file size %"PRIu64" is incorrect", FileDataSize(file));
4168  goto end;
4169  }
4170  static uint8_t org_binary[] = {
4171  0x4D, 0x5A, 0x00, 0x00, 0x50, 0x45, 0x00, 0x00,
4172  0x4C, 0x01, 0x01, 0x00, 0x6A, 0x2A, 0x58, 0xC3,
4173  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4174  0x04, 0x00, 0x03, 0x01, 0x0B, 0x01, 0x08, 0x00,
4175  0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
4176  0x79, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
4177  0x79, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
4178  0x00, 0x00, 0x40, 0x00, 0x04, 0x00, 0x00, 0x00,
4179  0x04, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00,
4180  0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
4181  0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00,
4182  0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4183  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4184  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4185  0x00, 0x00, 0x00, 0x00, 0x5C, 0x5C, 0x36, 0x36,
4186  0x2E, 0x39, 0x33, 0x2E, 0x36, 0x38, 0x2E, 0x36,
4187  0x5C, 0x7A, 0x00, 0x00, 0x38,};
4188 
4190  org_binary, sizeof(org_binary)) != 1)
4191  {
4192  printf("smtp-mime file data incorrect\n");
4193  goto end;
4194  }
4195  }
4196 
4197  /* DATA . reply */
4198  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4199  STREAM_TOCLIENT, reply4_end, reply4_end_len);
4200  if (r != 0) {
4201  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4202  goto end;
4203  }
4204  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
4206  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4207  goto end;
4208  }
4209 
4210  /* QUIT Request */
4211  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4212  STREAM_TOSERVER, request5, request5_len);
4213  if (r != 0) {
4214  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4215  goto end;
4216  }
4217  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
4218  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4220  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4221  goto end;
4222  }
4223 
4224  /* QUIT Reply */
4225  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4226  STREAM_TOCLIENT, reply5, reply5_len);
4227  if (r != 0) {
4228  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4229  goto end;
4230  }
4231  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
4233  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4234  goto end;
4235  }
4236 
4237  result = 1;
4238 end:
4239  if (alp_tctx != NULL)
4241  StreamTcpFreeConfig(true);
4242  FLOW_DESTROY(&f);
4243  return result;
4244 }
4245 #endif /* UNITTESTS */
4246 
4248 {
4249 #ifdef UNITTESTS
4250  UtRegisterTest("SMTPParserTest01", SMTPParserTest01);
4251  UtRegisterTest("SMTPParserTest02", SMTPParserTest02);
4252  UtRegisterTest("SMTPParserTest03", SMTPParserTest03);
4253  UtRegisterTest("SMTPParserTest04", SMTPParserTest04);
4254  UtRegisterTest("SMTPParserTest05", SMTPParserTest05);
4255  UtRegisterTest("SMTPParserTest06", SMTPParserTest06);
4256  UtRegisterTest("SMTPParserTest12", SMTPParserTest12);
4257  UtRegisterTest("SMTPParserTest13", SMTPParserTest13);
4258  UtRegisterTest("SMTPParserTest14", SMTPParserTest14);
4259 #endif /* UNITTESTS */
4260 }
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:1264
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:1531
StreamTcpReassemblySetMinInspectDepth
void StreamTcpReassemblySetMinInspectDepth(TcpSession *ssn, int direction, uint32_t depth)
Definition: stream-tcp-reassemble.c:2118
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:510
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:841
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:2611
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:1938
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:2587
SMTPThreadCtx_
Definition: app-layer-smtp.c:188
Packet_::flowflags
uint8_t flowflags
Definition: decode.h:504
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:292
SMTPConfig::raw_extraction
bool raw_extraction
Definition: app-layer-smtp.h:111
util-memcmp.h
MpmInitCtx
void MpmInitCtx(MpmCtx *mpm_ctx, uint8_t matcher)
Definition: util-mpm.c:210
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:461
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:1093
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:3347
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:2211
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:1771
AppLayerGetTxIterState
Definition: app-layer-parser.h:143
SMTP_REPLY_252
@ SMTP_REPLY_252
Definition: app-layer-smtp.c:207
Packet_
Definition: decode.h:473
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:1825
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:1108
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:1491
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:2144
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:1367
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:512
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:792
SCMapEnumNameToValue
int SCMapEnumNameToValue(const char *enum_name, SCEnumCharMap *table)
Maps a string name to an enum value from the supplied table. Please specify the last element of any m...
Definition: util-enum.c:40
flags
uint8_t flags
Definition: decode-gre.h:0
AppLayerParserParse
int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alproto, uint8_t flags, const uint8_t *input, uint32_t input_len)
Definition: app-layer-parser.c:1265
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:3574
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:601
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:2572
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:1862
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:843
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:4247
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:1760
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:1917
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:1261
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