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