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