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