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