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