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