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 (line->len >= 8 && SCMemcmpLowercase("starttls", line->buf, 8) == 0) {
1357  } else if (line->len >= 4 && SCMemcmpLowercase("data", line->buf, 4) == 0) {
1359  SMTPSetProgressTS(tx, SMTP_REQUEST_DATA);
1360  if (state->curr_tx->is_data) {
1361  // We did not receive a confirmation from server
1362  // And now client sends a next DATA
1363  SMTPSetEvent(state, SMTP_DECODER_EVENT_UNPARSABLE_CONTENT);
1364  SCReturnInt(0);
1365  } else if (smtp_config.raw_extraction) {
1367  (uint8_t *)rawmsgname, strlen(rawmsgname), NULL, 0,
1368  FILE_NOMD5 | FILE_NOMAGIC) == 0) {
1369  SMTPNewFile(tx, tx->files_ts.tail);
1370  }
1371  } else if (smtp_config.decode_mime) {
1373  tx->mime_state = SCMimeSmtpStateInit(&tx->files_ts, &smtp_config.sbcfg);
1374  if (tx->mime_state == NULL) {
1375  SCLogDebug("MimeDecInitParser() failed to "
1376  "allocate data");
1377  return -1;
1378  }
1379  }
1380  state->curr_tx->is_data = true;
1381 
1382  Frame *data_frame = AppLayerFrameNewByPointer(
1383  f, slice, input->buf + input->consumed, -1, 0, SMTP_FRAME_DATA);
1384  if (data_frame == NULL) {
1385  SCLogDebug("data_frame %p - no data frame set up", data_frame);
1386  } else {
1387  AppLayerFrameSetTxId(data_frame, state->curr_tx->tx_id);
1388  }
1389 
1390  /* Enter immediately data mode without waiting for server reply */
1393  }
1394  } else if (line->len >= 4 && SCMemcmpLowercase("bdat", line->buf, 4) == 0) {
1395  bool last = false;
1396  r = SMTPParseCommandBDAT(state, line, &last);
1397  if (r == -1) {
1398  /* Invalid BDAT syntax is recoverable: the server rejects the
1399  * command and the session continues. */
1400  SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_BDAT);
1402  r = 0;
1403  } else {
1405  SMTPSetProgressTS(tx, SMTP_REQUEST_DATA);
1406  if (state->bdat_chunk_len > 0) {
1408  } else if (last) {
1409  SMTPTransactionCompleteTS(tx);
1410  }
1411  }
1412  } else if (line->len >= 4 && ((SCMemcmpLowercase("helo", line->buf, 4) == 0) ||
1413  SCMemcmpLowercase("ehlo", line->buf, 4) == 0)) {
1414  r = SMTPParseCommandHELO(state, line);
1415  if (r == -1) {
1416  SCReturnInt(-1);
1417  }
1419  } else if (line->len >= 9 && SCMemcmpLowercase("mail from", line->buf, 9) == 0) {
1420  r = SMTPParseCommandMAILFROM(state, line);
1421  if (r == -1) {
1422  SCReturnInt(-1);
1423  }
1425  } else if (line->len >= 7 && SCMemcmpLowercase("rcpt to", line->buf, 7) == 0) {
1426  r = SMTPParseCommandRCPTTO(state, line);
1427  if (r == -1) {
1428  SCReturnInt(-1);
1429  }
1431  } else if (line->len >= 4 && SCMemcmpLowercase("rset", line->buf, 4) == 0) {
1432  // Resets chunk index in case of connection reuse
1433  state->bdat_chunk_idx = 0;
1435  } else if (line->len >= 4 && SCMemcmpLowercase("quit", line->buf, 4) == 0) {
1437  } else {
1439  }
1440 
1441  /* Every command is inserted into a command buffer, to be matched
1442  * against reply(ies) sent by the server */
1443  if (SMTPInsertCommandIntoCommandBuffer(state, state->current_command, tx) == -1) {
1444  SCReturnInt(-1);
1445  }
1446 
1447  SCReturnInt(r);
1448  }
1449 
1450  switch (state->current_command) {
1451  case SMTP_COMMAND_DATA:
1452  return SMTPProcessCommandDATA(state, tx, f, line);
1453 
1454  case SMTP_COMMAND_BDAT:
1456  return SMTPProcessCommandBDAT(state, tx, line);
1457 
1458  default:
1459  /* we have nothing to do with any other command at this instant.
1460  * Just let it go through */
1461  SCReturnInt(0);
1462  }
1463 }
1464 
1465 static inline void ResetLine(SMTPLine *line)
1466 {
1467  if (line != NULL) {
1468  line->len = 0;
1469  line->delim_len = 0;
1470  line->buf = NULL;
1471  }
1472 }
1473 
1474 static int SMTPPreProcessCommandBDAT(
1475  SMTPState *state, Flow *f, StreamSlice *slice, SMTPInput *input, SMTPLine *line)
1476 {
1477  if (state->bdat_chunk_idx >= state->bdat_chunk_len) {
1478  /* The BDAT chunk is already complete; data mode was set by another
1479  * command, such as a pipelined DATA reply. Leave data mode and let
1480  * the line parser handle the input as a new command. */
1482  return 1;
1483  }
1484  uint32_t remaining = state->bdat_chunk_len - state->bdat_chunk_idx;
1485  uint32_t consumed = MIN((uint32_t)input->len, remaining);
1486  line->buf = input->buf + input->consumed;
1487  line->len = consumed;
1488  input->consumed += consumed;
1489  input->len -= consumed;
1490  int ret = SMTPProcessRequest(state, f, input, line, slice);
1491  ResetLine(line);
1492  return ret;
1493 }
1494 
1495 /*
1496  * @brief Pre-process command data.
1497  *
1498  * If the command being processed is DATA, its data must be handled by this
1499  * function so the line limit used by GetLine is not applied. GetLine caps lines
1500  * at SMTP_LINE_BUFFER_LIMIT, which could truncate file data or parts of an
1501  * e-mail if a line were too long.
1502  *
1503  * BDAT data is octet-counted and must be consumed only up to the declared chunk
1504  * boundary.
1505  *
1506  * @param state Pointer to the current SMTPState
1507  * @param f Pointer to the current Flow
1508  * @param pstate Pointer to the current AppLayerParserState
1509  * @param input Pointer to the current input data to SMTP parser
1510  * @param line Pointer to the current line being parsed by the SMTP parser
1511  * @return 0 for success
1512  * 1 for handing control over to GetLine
1513  * -1 for errors and inconsistent states
1514  * */
1515 static int SMTPPreProcessCommands(
1516  SMTPState *state, Flow *f, StreamSlice *slice, SMTPInput *input, SMTPLine *line)
1517 {
1519  DEBUG_VALIDATE_BUG_ON(line->len != 0);
1520  DEBUG_VALIDATE_BUG_ON(line->delim_len != 0);
1521 
1522  if (state->current_command == SMTP_COMMAND_BDAT ||
1524  return SMTPPreProcessCommandBDAT(state, f, slice, input, line);
1525  }
1526 
1527  /* fall back to strict line parsing for mime header parsing */
1528  if (state->curr_tx && state->curr_tx->mime_state &&
1529  SCMimeSmtpGetState(state->curr_tx->mime_state) < MimeSmtpBody)
1530  return 1;
1531 
1532  bool line_complete = false;
1533  const int32_t input_len = input->len;
1534  const int32_t offset = input->consumed;
1535  for (int32_t i = 0; i < input_len; i++) {
1536  if (input->buf[offset + i] == 0x0d) {
1537  if (i < input_len - 1 && input->buf[offset + i + 1] == 0x0a) {
1538  i++;
1539  line->delim_len++;
1540  }
1541  /* Line is just ending in CR */
1542  line->delim_len++;
1543  line_complete = true;
1544  } else if (input->buf[offset + i] == 0x0a) {
1545  /* Line is just ending in LF */
1546  line->delim_len++;
1547  line_complete = true;
1548  }
1549  /* Either line is complete or fragmented */
1550  if (line_complete || (i == input_len - 1)) {
1551  DEBUG_VALIDATE_BUG_ON(input->consumed + input->len != input->orig_len);
1552  DEBUG_VALIDATE_BUG_ON(input->len == 0 && input_len != 0);
1553  /* state->input_len reflects data from start of the line in progress. */
1554  if ((input->len == 1 && input->buf[input->consumed] == '-') ||
1555  (input->len > 1 && input->buf[input->consumed] == '-' &&
1556  input->buf[input->consumed + 1] == '-')) {
1557  SCLogDebug("Possible boundary, yield to GetLine");
1558  return 1;
1559  }
1560  /* total_consumed should be input consumed so far + i + 1 */
1561  int32_t total_consumed = offset + i + 1;
1562  int32_t current_line_consumed = total_consumed - input->consumed;
1563  DEBUG_VALIDATE_BUG_ON(current_line_consumed < line->delim_len);
1564  line->buf = input->buf + input->consumed;
1565  line->len = current_line_consumed - line->delim_len;
1566  DEBUG_VALIDATE_BUG_ON(line->len < 0);
1567  if (line->len < 0) {
1568  return -1;
1569  }
1570 
1571  input->consumed = total_consumed;
1572  input->len -= current_line_consumed;
1573  DEBUG_VALIDATE_BUG_ON(input->consumed + input->len != input->orig_len);
1574  if (SMTPProcessRequest(state, f, input, line, slice) == -1) {
1575  return -1;
1576  }
1577  line_complete = false;
1578  line->buf = NULL;
1579  line->len = 0;
1580  line->delim_len = 0;
1581 
1582  /* bail if `SMTPProcessRequest` ended the data mode */
1583  if ((state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE) == 0) {
1585  if (data_frame) {
1586  data_frame->len = (slice->offset + input->consumed) - data_frame->offset;
1587  }
1588  break;
1589  }
1590  }
1591  }
1592  return 0;
1593 }
1594 
1595 static AppLayerResult SMTPParse(uint8_t direction, Flow *f, SMTPState *state,
1596  AppLayerParserState *pstate, StreamSlice stream_slice, SMTPThreadCtx *thread_data)
1597 {
1598  SCEnter();
1599 
1600  const uint8_t *input_buf = StreamSliceGetData(&stream_slice);
1601  uint32_t input_len = StreamSliceGetDataLen(&stream_slice);
1602 
1603  if (input_buf == NULL &&
1604  ((direction == 0 && SCAppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TS)) ||
1605  (direction == 1 &&
1606  SCAppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TC)))) {
1608  } else if (input_buf == NULL || input_len == 0) {
1610  }
1611 
1612  SMTPInput input = { .buf = input_buf, .len = input_len, .orig_len = input_len, .consumed = 0 };
1613  SMTPLine line = { NULL, 0, 0, false };
1614 
1615  /* toserver */
1616  if (direction == 0) {
1617  if (((state->current_command == SMTP_COMMAND_DATA) ||
1618  (state->current_command == SMTP_COMMAND_BDAT) ||
1619  (state->current_command == SMTP_COMMAND_BDAT_LAST)) &&
1621  int ret = SMTPPreProcessCommands(state, f, &stream_slice, &input, &line);
1622  DEBUG_VALIDATE_BUG_ON(ret != 0 && ret != -1 && ret != 1);
1623  if (ret == 0 && input.consumed == input.orig_len) {
1625  } else if (ret < 0) {
1627  }
1628  }
1629  AppLayerResult res = SMTPGetLine(f, &stream_slice, state, &input, &line, direction);
1630  while (res.status == 0) {
1631  int retval = SMTPProcessRequest(state, f, &input, &line, &stream_slice);
1632  if (retval != 0)
1634  if (line.delim_len == 0 && line.len == SMTP_LINE_BUFFER_LIMIT) {
1635  if (!line.lf_found) {
1636  state->discard_till_lf_ts = true;
1637  }
1638  input.consumed = input.len + 1; // For the newly found LF
1639  SMTPSetEvent(state, SMTP_DECODER_EVENT_TRUNCATED_LINE);
1640  break;
1641  }
1642  /* If request was successfully parsed, reset line as it has already been used
1643  * wherever it had to be */
1644  ResetLine(&line);
1645 
1646  /* If command data mode was entered in the middle of input parsing, first pass it to
1647  * SMTPPreProcessCommands so input limits are not applied to DATA bodies and BDAT data
1648  * is not consumed past its chunk boundary. SMTPPreProcessCommands should either
1649  * consume all remaining input or stop at a MIME or BDAT chunk boundary, after which
1650  * control is passed to SMTPGetLine. */
1651  if ((input.len > 0) &&
1652  ((state->current_command == SMTP_COMMAND_DATA) ||
1653  (state->current_command == SMTP_COMMAND_BDAT) ||
1654  (state->current_command == SMTP_COMMAND_BDAT_LAST)) &&
1656  int ret = SMTPPreProcessCommands(state, f, &stream_slice, &input, &line);
1657  DEBUG_VALIDATE_BUG_ON(ret != 0 && ret != -1 && ret != 1);
1658  if (ret == 0 && input.consumed == input.orig_len) {
1660  } else if (ret < 0) {
1662  }
1663  }
1664  res = SMTPGetLine(f, &stream_slice, state, &input, &line, direction);
1665  }
1666  if (res.status == 1)
1667  return res;
1668  /* toclient */
1669  } else {
1670  AppLayerResult res = SMTPGetLine(f, &stream_slice, state, &input, &line, direction);
1671  while (res.status == 0) {
1672  if (SMTPProcessReply(state, f, thread_data, &input, &line) != 0)
1674  if (line.delim_len == 0 && line.len == SMTP_LINE_BUFFER_LIMIT) {
1675  if (!line.lf_found) {
1676  state->discard_till_lf_tc = true;
1677  }
1678  input.consumed = input.len + 1; // For the newly found LF
1679  SMTPSetEvent(state, SMTP_DECODER_EVENT_TRUNCATED_LINE);
1680  break;
1681  }
1682  res = SMTPGetLine(f, &stream_slice, state, &input, &line, direction);
1683  }
1684  if (res.status == 1)
1685  return res;
1686  }
1687 
1689 }
1690 
1691 static AppLayerResult SMTPParseClientRecord(Flow *f, void *alstate, AppLayerParserState *pstate,
1692  StreamSlice stream_slice, void *local_data)
1693 {
1694  SCEnter();
1695 
1696  /* first arg 0 is toserver */
1697  return SMTPParse(0, f, alstate, pstate, stream_slice, local_data);
1698 }
1699 
1700 static AppLayerResult SMTPParseServerRecord(Flow *f, void *alstate, AppLayerParserState *pstate,
1701  StreamSlice stream_slice, void *local_data)
1702 {
1703  SCEnter();
1704 
1705  /* first arg 1 is toclient */
1706  return SMTPParse(1, f, alstate, pstate, stream_slice, local_data);
1707 }
1708 
1709 /**
1710  * \internal
1711  * \brief Function to allocate SMTP state memory.
1712  */
1713 void *SMTPStateAlloc(void *orig_state, AppProto proto_orig)
1714 {
1715  SMTPState *smtp_state = SCCalloc(1, sizeof(SMTPState));
1716  if (unlikely(smtp_state == NULL))
1717  return NULL;
1718 
1719  smtp_state->cmds = SCMalloc(sizeof(uint8_t) *
1721  if (smtp_state->cmds == NULL) {
1722  SCFree(smtp_state);
1723  return NULL;
1724  }
1725  smtp_state->cmds_tx_ids = SCMalloc(sizeof(uint64_t) * SMTP_COMMAND_BUFFER_STEPS);
1726  if (smtp_state->cmds_tx_ids == NULL) {
1727  SCFree(smtp_state->cmds);
1728  SCFree(smtp_state);
1729  return NULL;
1730  }
1732 
1733  TAILQ_INIT(&smtp_state->tx_list);
1734 
1735  return smtp_state;
1736 }
1737 
1738 static SMTPString *SMTPStringAlloc(void)
1739 {
1740  SMTPString *smtp_string = SCCalloc(1, sizeof(SMTPString));
1741  if (unlikely(smtp_string == NULL))
1742  return NULL;
1743 
1744  return smtp_string;
1745 }
1746 
1747 
1748 static void SMTPStringFree(SMTPString *str)
1749 {
1750  if (str->str) {
1751  SCFree(str->str);
1752  }
1753  SCFree(str);
1754 }
1755 
1756 static void *SMTPLocalStorageAlloc(void)
1757 {
1758  /* needed by the mpm */
1759  SMTPThreadCtx *td = SCCalloc(1, sizeof(*td));
1760  if (td == NULL) {
1761  exit(EXIT_FAILURE);
1762  }
1763 
1764  td->pmq = SCCalloc(1, sizeof(*td->pmq));
1765  if (td->pmq == NULL) {
1766  exit(EXIT_FAILURE);
1767  }
1768  PmqSetup(td->pmq);
1769 
1770  td->smtp_mpm_thread_ctx = SCCalloc(1, sizeof(MpmThreadCtx));
1771  if (unlikely(td->smtp_mpm_thread_ctx == NULL)) {
1772  exit(EXIT_FAILURE);
1773  }
1774  MpmInitThreadCtx(td->smtp_mpm_thread_ctx, smtp_mpm_ctx, SMTP_MPM);
1775  return td;
1776 }
1777 
1778 static void SMTPLocalStorageFree(void *ptr)
1779 {
1780  SMTPThreadCtx *td = ptr;
1781  if (td != NULL) {
1782  if (td->pmq != NULL) {
1783  PmqFree(td->pmq);
1784  SCFree(td->pmq);
1785  }
1786 
1787  if (td->smtp_mpm_thread_ctx != NULL) {
1790  }
1791 
1792  SCFree(td);
1793  }
1794 }
1795 
1796 static void SMTPTransactionFree(SMTPTransaction *tx, SMTPState *state)
1797 {
1798  if (tx->mime_state != NULL) {
1799  SCMimeSmtpStateFree(tx->mime_state);
1800  }
1801 
1803 
1804  if (tx->mail_from)
1805  SCFree(tx->mail_from);
1806 
1807  SMTPString *str = NULL;
1808  while ((str = TAILQ_FIRST(&tx->rcpt_to_list))) {
1809  TAILQ_REMOVE(&tx->rcpt_to_list, str, next);
1810  SMTPStringFree(str);
1811  }
1813 
1814  SCFree(tx);
1815 }
1816 
1817 /**
1818  * \internal
1819  * \brief Function to free SMTP state memory.
1820  */
1821 static void SMTPStateFree(void *p)
1822 {
1823  SMTPState *smtp_state = (SMTPState *)p;
1824 
1825  if (smtp_state->cmds != NULL) {
1826  SCFree(smtp_state->cmds);
1827  }
1828  if (smtp_state->cmds_tx_ids != NULL) {
1829  SCFree(smtp_state->cmds_tx_ids);
1830  }
1831 
1832  if (smtp_state->helo) {
1833  SCFree(smtp_state->helo);
1834  }
1835 
1836  SMTPTransaction *tx = NULL;
1837  while ((tx = TAILQ_FIRST(&smtp_state->tx_list))) {
1838  TAILQ_REMOVE(&smtp_state->tx_list, tx, next);
1839  SMTPTransactionFree(tx, smtp_state);
1840  }
1841 
1842  SCFree(smtp_state);
1843 }
1844 
1845 static void SMTPSetMpmState(void)
1846 {
1847  smtp_mpm_ctx = SCCalloc(1, sizeof(MpmCtx));
1848  if (unlikely(smtp_mpm_ctx == NULL)) {
1849  exit(EXIT_FAILURE);
1850  }
1851  MpmInitCtx(smtp_mpm_ctx, SMTP_MPM);
1852 
1853  uint32_t i = 0;
1854  for (i = 0; i < sizeof(smtp_reply_map)/sizeof(SCEnumCharMap) - 1; i++) {
1855  SCEnumCharMap *map = &smtp_reply_map[i];
1856  /* The third argument is 3, because reply code is always 3 bytes. */
1857  SCMpmAddPatternCI(smtp_mpm_ctx, (uint8_t *)map->enum_name, 3, 0 /* defunct */,
1858  0 /* defunct */, i /* pattern id */, i /* rule id */, 0 /* no flags */);
1859  }
1860 
1861  mpm_table[SMTP_MPM].Prepare(NULL, smtp_mpm_ctx);
1862 }
1863 
1864 static void SMTPFreeMpmState(void)
1865 {
1866  if (smtp_mpm_ctx != NULL) {
1867  mpm_table[SMTP_MPM].DestroyCtx(smtp_mpm_ctx);
1868  SCFree(smtp_mpm_ctx);
1869  smtp_mpm_ctx = NULL;
1870  }
1871 }
1872 
1873 static int SMTPStateGetEventInfo(
1874  const char *event_name, uint8_t *event_id, AppLayerEventType *event_type)
1875 {
1876  if (SCAppLayerGetEventIdByName(event_name, smtp_decoder_event_table, event_id) == 0) {
1877  *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
1878  return 0;
1879  }
1880  return -1;
1881 }
1882 
1883 static int SMTPStateGetEventInfoById(
1884  uint8_t event_id, const char **event_name, AppLayerEventType *event_type)
1885 {
1886  *event_name = SCMapEnumValueToName(event_id, smtp_decoder_event_table);
1887  if (*event_name == NULL) {
1888  SCLogError("event \"%d\" not present in "
1889  "smtp's enum map table.",
1890  event_id);
1891  /* yes this is fatal */
1892  return -1;
1893  }
1894 
1895  *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
1896 
1897  return 0;
1898 }
1899 
1900 // This probing parser checks the port after ambiguous patterns
1901 // that may be used by other protocols such as FTP
1902 static AppProto SMTPClientProbingParserCheckPort(
1903  const Flow *f, uint8_t direction, const uint8_t *input, uint32_t len, uint8_t *rdir)
1904 {
1905  if (AppLayerProtoDetectHasProbingParsers(IPPROTO_TCP, f->dp, ALPROTO_FTP)) {
1906  return ALPROTO_FAILED;
1907  }
1908  return ALPROTO_SMTP;
1909 }
1910 
1911 static AppProto SMTPServerProbingParser(
1912  const Flow *f, uint8_t direction, const uint8_t *input, uint32_t len, uint8_t *rdir)
1913 {
1914  // another check for minimum length
1915  if (len < 5) {
1916  return ALPROTO_UNKNOWN;
1917  }
1918  // begins by 220
1919  if (input[0] != '2' || input[1] != '2' || input[2] != '0') {
1920  return ALPROTO_FAILED;
1921  }
1922  // followed by space or hypen
1923  if (input[3] != ' ' && input[3] != '-') {
1924  return ALPROTO_FAILED;
1925  }
1926  // If client side is SMTP, do not validate domain
1927  // so that server banner can be parsed first.
1928  if (f->alproto_ts == ALPROTO_SMTP) {
1929  if (memchr(input + 4, '\n', len - 4) != NULL) {
1930  return ALPROTO_SMTP;
1931  }
1932  return ALPROTO_UNKNOWN;
1933  }
1935  if (f->todstbytecnt > 4 && (f->alproto_ts == ALPROTO_UNKNOWN || f->alproto_ts == ALPROTO_TLS)) {
1936  // Only validates SMTP if client side is unknown
1937  // despite having received bytes.
1938  r = ALPROTO_SMTP;
1939  }
1940  uint32_t offset = SCValidateDomain(input + 4, len - 4);
1941  if (offset == 0) {
1942  return ALPROTO_FAILED;
1943  }
1944  if (r != ALPROTO_UNKNOWN && memchr(input + 4, '\n', len - 4) != NULL) {
1945  return r;
1946  }
1947  // This should not go forever because of engine limiting probing parsers.
1948  return ALPROTO_UNKNOWN;
1949 }
1950 
1951 static int SMTPRegisterPatternsForProtocolDetection(void)
1952 {
1954  IPPROTO_TCP, ALPROTO_SMTP, "EHLO", 4, 0, STREAM_TOSERVER) < 0) {
1955  return -1;
1956  }
1958  IPPROTO_TCP, ALPROTO_SMTP, "HELO", 4, 0, STREAM_TOSERVER) < 0) {
1959  return -1;
1960  }
1961  if (SCAppLayerProtoDetectPMRegisterPatternCIwPP(IPPROTO_TCP, ALPROTO_SMTP, "QUIT", 4, 0,
1962  STREAM_TOSERVER, SMTPClientProbingParserCheckPort, 4, 4) < 0) {
1963  return -1;
1964  }
1965 
1967  "tcp", IPPROTO_TCP, "smtp", ALPROTO_SMTP, 0, 5, NULL, SMTPServerProbingParser)) {
1968  // STREAM_TOSERVER means here use 25 as flow destination port
1969  SCAppLayerProtoDetectPPRegister(IPPROTO_TCP, "25,465", ALPROTO_SMTP, 0, 5, STREAM_TOSERVER,
1970  NULL, SMTPServerProbingParser);
1971  }
1972 
1973  return 0;
1974 }
1975 
1976 static void SMTPStateTransactionFree (void *state, uint64_t tx_id)
1977 {
1978  SMTPState *smtp_state = state;
1979  SMTPTransaction *tx = NULL;
1980  TAILQ_FOREACH(tx, &smtp_state->tx_list, next) {
1981  if (tx_id < tx->tx_id)
1982  break;
1983  else if (tx_id > tx->tx_id)
1984  continue;
1985 
1986  if (tx == smtp_state->curr_tx)
1987  smtp_state->curr_tx = NULL;
1988  TAILQ_REMOVE(&smtp_state->tx_list, tx, next);
1989  SMTPTransactionFree(tx, state);
1990  break;
1991  }
1992 
1993 
1994 }
1995 
1996 /** \retval cnt highest tx id */
1997 static uint64_t SMTPStateGetTxCnt(void *state)
1998 {
1999  uint64_t cnt = 0;
2000  SMTPState *smtp_state = state;
2001  if (smtp_state) {
2002  cnt = smtp_state->tx_cnt;
2003  }
2004  SCLogDebug("returning %"PRIu64, cnt);
2005  return cnt;
2006 }
2007 
2008 static void *SMTPStateGetTx(void *state, uint64_t id)
2009 {
2010  SMTPState *smtp_state = state;
2011  if (smtp_state) {
2012  SMTPTransaction *tx = NULL;
2013 
2014  if (smtp_state->curr_tx == NULL)
2015  return NULL;
2016  if (smtp_state->curr_tx->tx_id == id)
2017  return smtp_state->curr_tx;
2018 
2019  TAILQ_FOREACH(tx, &smtp_state->tx_list, next) {
2020  if (tx->tx_id == id)
2021  return tx;
2022  }
2023  }
2024  return NULL;
2025 }
2026 
2027 static int SMTPStateGetAlstateProgress(void *vtx, uint8_t direction)
2028 {
2029  SMTPTransaction *tx = vtx;
2030  if (direction & STREAM_TOSERVER) {
2031  return tx->progress_ts;
2032  }
2033  return tx->progress_tc;
2034 }
2035 
2036 static AppLayerGetFileState SMTPGetTxFiles(void *txv, uint8_t direction)
2037 {
2038  AppLayerGetFileState files = { .fc = NULL, .cfg = &smtp_config.sbcfg };
2039  SMTPTransaction *tx = (SMTPTransaction *)txv;
2040 
2041  if (direction & STREAM_TOSERVER) {
2042  files.fc = &tx->files_ts;
2043  }
2044  return files;
2045 }
2046 
2047 static AppLayerTxData *SMTPGetTxData(void *vtx)
2048 {
2049  SMTPTransaction *tx = (SMTPTransaction *)vtx;
2050  return &tx->tx_data;
2051 }
2052 
2053 static AppLayerStateData *SMTPGetStateData(void *vstate)
2054 {
2055  SMTPState *state = (SMTPState *)vstate;
2056  return &state->state_data;
2057 }
2058 
2059 /** \brief SMTP tx iterator, specialized for its linked list
2060  *
2061  * \retval txptr or NULL if no more txs in list
2062  */
2063 static AppLayerGetTxIterTuple SMTPGetTxIterator(const uint8_t ipproto, const AppProto alproto,
2064  void *alstate, uint64_t min_tx_id, uint64_t max_tx_id, AppLayerGetTxIterState *state)
2065 {
2066  SMTPState *smtp_state = (SMTPState *)alstate;
2067  AppLayerGetTxIterTuple no_tuple = { NULL, 0, false };
2068  if (smtp_state) {
2069  SMTPTransaction *tx_ptr;
2070  if (state->un.ptr == NULL) {
2071  tx_ptr = TAILQ_FIRST(&smtp_state->tx_list);
2072  } else {
2073  tx_ptr = (SMTPTransaction *)state->un.ptr;
2074  }
2075  if (tx_ptr) {
2076  while (tx_ptr->tx_id < min_tx_id) {
2077  tx_ptr = TAILQ_NEXT(tx_ptr, next);
2078  if (!tx_ptr) {
2079  return no_tuple;
2080  }
2081  }
2082  if (tx_ptr->tx_id >= max_tx_id) {
2083  return no_tuple;
2084  }
2085  state->un.ptr = TAILQ_NEXT(tx_ptr, next);
2086  AppLayerGetTxIterTuple tuple = {
2087  .tx_ptr = tx_ptr,
2088  .tx_id = tx_ptr->tx_id,
2089  .has_next = (state->un.ptr != NULL),
2090  };
2091  return tuple;
2092  }
2093  }
2094  return no_tuple;
2095 }
2096 
2097 /**
2098  * \brief Register the SMTP Protocol parser.
2099  */
2101 {
2102  const char *proto_name = "smtp";
2103 
2104  if (SCAppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
2106  if (SMTPRegisterPatternsForProtocolDetection() < 0 )
2107  return;
2108  } else {
2109  SCLogInfo("Protocol detection and parser disabled for %s protocol.",
2110  proto_name);
2111  return;
2112  }
2113 
2114  if (SCAppLayerParserConfParserEnabled("tcp", proto_name)) {
2115  AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateAlloc, SMTPStateFree);
2116 
2117  AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_SMTP, STREAM_TOSERVER,
2118  SMTPParseClientRecord);
2119  AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_SMTP, STREAM_TOCLIENT,
2120  SMTPParseServerRecord);
2121 
2122  AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetEventInfo);
2123  AppLayerParserRegisterGetEventInfoById(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetEventInfoById);
2124 
2125  AppLayerParserRegisterLocalStorageFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPLocalStorageAlloc,
2126  SMTPLocalStorageFree);
2127 
2128  AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateTransactionFree);
2129  AppLayerParserRegisterGetTxFilesFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetTxFiles);
2130  AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetAlstateProgress);
2131  AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTxCnt);
2132  AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTx);
2133  AppLayerParserRegisterGetTxIterator(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetTxIterator);
2134  AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetTxData);
2135  AppLayerParserRegisterStateDataFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetStateData);
2139  IPPROTO_TCP, ALPROTO_SMTP, SMTPGetFrameIdByName, SMTPGetFrameNameById);
2141  IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetStateIdByName, SMTPStateGetStateNameById);
2142  } else {
2143  SCLogInfo("Parser disabled for %s protocol. Protocol detection still on.", proto_name);
2144  }
2145 
2146  SMTPSetMpmState();
2147 
2148  SMTPConfigure();
2149 
2150 #ifdef UNITTESTS
2152 #endif
2153 }
2154 
2155 /**
2156  * \brief Free memory allocated for global SMTP parser state.
2157  */
2159 {
2160  SMTPFreeMpmState();
2161 }
2162 
2163 /***************************************Unittests******************************/
2164 
2165 #ifdef UNITTESTS
2166 #include "detect-engine-alert.h"
2167 
2168 static void SMTPTestInitConfig(void)
2169 {
2173 
2175 
2177 }
2178 
2179 /*
2180  * \test Test STARTTLS.
2181  */
2182 static int SMTPParserTest01(void)
2183 {
2184  int result = 0;
2185  Flow f;
2186  int r = 0;
2187 
2188  /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
2189  uint8_t welcome_reply[] = {
2190  0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
2191  0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
2192  0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
2193  0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
2194  0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
2195  0x0d, 0x0a
2196  };
2197  uint32_t welcome_reply_len = sizeof(welcome_reply);
2198 
2199  /* EHLO [192.168.0.158]<CR><LF> */
2200  uint8_t request1[] = {
2201  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x5b, 0x31, 0x39,
2202  0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e,
2203  0x31, 0x35, 0x38, 0x5d, 0x0d, 0x0a
2204  };
2205  uint32_t request1_len = sizeof(request1);
2206  /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
2207  * 250-SIZE 35882577<CR><LF>
2208  * 250-8BITMIME<CR><LF>
2209  * 250-STARTTLS<CR><LF>
2210  * 250 ENHANCEDSTATUSCODES<CR><LF>
2211  */
2212  uint8_t reply1[] = {
2213  0x32, 0x35, 0x30, 0x2d, 0x6d, 0x78, 0x2e, 0x67,
2214  0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
2215  0x6d, 0x20, 0x61, 0x74, 0x20, 0x79, 0x6f, 0x75,
2216  0x72, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
2217  0x65, 0x2c, 0x20, 0x5b, 0x31, 0x31, 0x37, 0x2e,
2218  0x31, 0x39, 0x38, 0x2e, 0x31, 0x31, 0x35, 0x2e,
2219  0x35, 0x30, 0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30,
2220  0x2d, 0x53, 0x49, 0x5a, 0x45, 0x20, 0x33, 0x35,
2221  0x38, 0x38, 0x32, 0x35, 0x37, 0x37, 0x0d, 0x0a,
2222  0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49, 0x54,
2223  0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35,
2224  0x30, 0x2d, 0x53, 0x54, 0x41, 0x52, 0x54, 0x54,
2225  0x4c, 0x53, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20,
2226  0x45, 0x4e, 0x48, 0x41, 0x4e, 0x43, 0x45, 0x44,
2227  0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x43, 0x4f,
2228  0x44, 0x45, 0x53, 0x0d, 0x0a
2229  };
2230  uint32_t reply1_len = sizeof(reply1);
2231 
2232  /* STARTTLS<CR><LF> */
2233  uint8_t request2[] = {
2234  0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
2235  0x0d, 0x0a
2236  };
2237  uint32_t request2_len = sizeof(request2);
2238  /* 220 2.0.0 Ready to start TLS<CR><LF> */
2239  uint8_t reply2[] = {
2240  0x32, 0x32, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
2241  0x30, 0x20, 0x52, 0x65, 0x61, 0x64, 0x79, 0x20,
2242  0x74, 0x6f, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74,
2243  0x20, 0x54, 0x4c, 0x53, 0x0d, 0x0a
2244  };
2245  uint32_t reply2_len = sizeof(reply2);
2246 
2247  TcpSession ssn;
2249 
2250  memset(&f, 0, sizeof(f));
2251  memset(&ssn, 0, sizeof(ssn));
2252 
2253  FLOW_INITIALIZE(&f);
2254  f.protoctx = (void *)&ssn;
2255  f.proto = IPPROTO_TCP;
2256  f.alproto = ALPROTO_SMTP;
2257 
2258  StreamTcpInitConfig(true);
2259  SMTPTestInitConfig();
2260 
2261  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2262  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
2263  if (r != 0) {
2264  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2265  goto end;
2266  }
2267  SMTPState *smtp_state = f.alstate;
2268  if (smtp_state == NULL) {
2269  printf("no smtp state: ");
2270  goto end;
2271  }
2272  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2274  printf("smtp parser in inconsistent state\n");
2275  goto end;
2276  }
2277 
2278  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2279  STREAM_TOSERVER, request1, request1_len);
2280  if (r != 0) {
2281  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2282  goto end;
2283  }
2284  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2285  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2287  printf("smtp parser in inconsistent state\n");
2288  goto end;
2289  }
2290 
2291  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2292  STREAM_TOCLIENT, reply1, reply1_len);
2293  if (r != 0) {
2294  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2295  goto end;
2296  }
2297  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2299  printf("smtp parser in inconsistent state\n");
2300  goto end;
2301  }
2302 
2303  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2304  STREAM_TOSERVER, request2, request2_len);
2305  if (r != 0) {
2306  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2307  goto end;
2308  }
2309  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2310  smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS ||
2312  printf("smtp parser in inconsistent state\n");
2313  goto end;
2314  }
2315 
2316  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2317  STREAM_TOCLIENT, reply2, reply2_len);
2318  if (r != 0) {
2319  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2320  goto end;
2321  }
2322  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2323  smtp_state->parser_state !=
2325  printf("smtp parser in inconsistent state\n");
2326  goto end;
2327  }
2328 
2329  if (!FlowChangeProto(&f)) {
2330  goto end;
2331  }
2332 
2333  result = 1;
2334 end:
2335  FLOW_DESTROY(&f);
2336  if (alp_tctx != NULL)
2338  StreamTcpFreeConfig(true);
2339  return result;
2340 }
2341 
2342 /**
2343  * \test Test multiple DATA commands(full mail transactions).
2344  */
2345 static int SMTPParserTest02(void)
2346 {
2347  int result = 0;
2348  Flow f;
2349  int r = 0;
2350 
2351  /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
2352  uint8_t welcome_reply[] = {
2353  0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
2354  0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
2355  0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
2356  0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
2357  0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
2358  0x0d, 0x0a
2359  };
2360  uint32_t welcome_reply_len = sizeof(welcome_reply);
2361 
2362  /* EHLO boo.com<CR><LF> */
2363  uint8_t request1[] = {
2364  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
2365  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
2366  };
2367  uint32_t request1_len = sizeof(request1);
2368  /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
2369  * 250-SIZE 35882577<CR><LF>
2370  * 250-8BITMIME<CR><LF>
2371  * 250-STARTTLS<CR><LF>
2372  * 250 ENHANCEDSTATUSCODES<CR><LF>
2373  */
2374  uint8_t reply1[] = {
2375  0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
2376  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2377  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2378  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
2379  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
2380  0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
2381  0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
2382  0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
2383  0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
2384  0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
2385  0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
2386  0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
2387  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
2388  0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
2389  0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
2390  };
2391  uint32_t reply1_len = sizeof(reply1);
2392 
2393  /* MAIL FROM:asdff@asdf.com<CR><LF> */
2394  uint8_t request2[] = {
2395  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
2396  0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
2397  0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
2398  0x0d, 0x0a
2399  };
2400  uint32_t request2_len = sizeof(request2);
2401  /* 250 2.1.0 Ok<CR><LF> */
2402  uint8_t reply2[] = {
2403  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2404  0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2405  };
2406  uint32_t reply2_len = sizeof(reply2);
2407 
2408  /* RCPT TO:bimbs@gmail.com<CR><LF> */
2409  uint8_t request3[] = {
2410  0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
2411  0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
2412  0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
2413  0x0a
2414  };
2415  uint32_t request3_len = sizeof(request3);
2416  /* 250 2.1.5 Ok<CR><LF> */
2417  uint8_t reply3[] = {
2418  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2419  0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2420  };
2421  uint32_t reply3_len = sizeof(reply3);
2422 
2423  /* DATA<CR><LF> */
2424  uint8_t request4[] = {
2425  0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
2426  };
2427  uint32_t request4_len = sizeof(request4);
2428  /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
2429  uint8_t reply4[] = {
2430  0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
2431  0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
2432  0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
2433  0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
2434  0x4c, 0x46, 0x3e, 0x0d, 0x0a
2435  };
2436  uint32_t reply4_len = sizeof(reply4);
2437 
2438  /* FROM:asdff@asdf.com<CR><LF> */
2439  uint8_t request5_1[] = {
2440  0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
2441  0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
2442  0x63, 0x6f, 0x6d, 0x0d, 0x0a
2443  };
2444  uint32_t request5_1_len = sizeof(request5_1);
2445  /* TO:bimbs@gmail.com<CR><LF> */
2446  uint8_t request5_2[] = {
2447  0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73,
2448  0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63,
2449  0x6f, 0x6d, 0x0d, 0x0a
2450  };
2451  uint32_t request5_2_len = sizeof(request5_2);
2452  /* <CR><LF> */
2453  uint8_t request5_3[] = {
2454  0x0d, 0x0a
2455  };
2456  uint32_t request5_3_len = sizeof(request5_3);
2457  /* this is test mail1<CR><LF> */
2458  uint8_t request5_4[] = {
2459  0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
2460  0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x69,
2461  0x6c, 0x31, 0x0d, 0x0a
2462  };
2463  uint32_t request5_4_len = sizeof(request5_4);
2464  /* .<CR><LF> */
2465  uint8_t request5_5[] = {
2466  0x2e, 0x0d, 0x0a
2467  };
2468  uint32_t request5_5_len = sizeof(request5_5);
2469  /* 250 2.0.0 Ok: queued as 6A1AF20BF2<CR><LF> */
2470  uint8_t reply5[] = {
2471  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
2472  0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
2473  0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
2474  0x36, 0x41, 0x31, 0x41, 0x46, 0x32, 0x30, 0x42,
2475  0x46, 0x32, 0x0d, 0x0a
2476  };
2477  uint32_t reply5_len = sizeof(reply5);
2478 
2479  /* MAIL FROM:asdfg@asdf.com<CR><LF> */
2480  uint8_t request6[] = {
2481  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
2482  0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x67, 0x40,
2483  0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
2484  0x0d, 0x0a
2485  };
2486  uint32_t request6_len = sizeof(request6);
2487  /* 250 2.1.0 Ok<CR><LF> */
2488  uint8_t reply6[] = {
2489  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2490  0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2491  };
2492  uint32_t reply6_len = sizeof(reply6);
2493 
2494  /* RCPT TO:bimbs@gmail.com<CR><LF> */
2495  uint8_t request7[] = {
2496  0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
2497  0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
2498  0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
2499  0x0a
2500  };
2501  uint32_t request7_len = sizeof(request7);
2502  /* 250 2.1.5 Ok<CR><LF> */
2503  uint8_t reply7[] = {
2504  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2505  0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2506  };
2507  uint32_t reply7_len = sizeof(reply7);
2508 
2509  /* DATA<CR><LF> */
2510  uint8_t request8[] = {
2511  0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
2512  };
2513  uint32_t request8_len = sizeof(request8);
2514  /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
2515  uint8_t reply8[] = {
2516  0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
2517  0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
2518  0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
2519  0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
2520  0x4c, 0x46, 0x3e, 0x0d, 0x0a
2521  };
2522  uint32_t reply8_len = sizeof(reply8);
2523 
2524  /* FROM:asdfg@gmail.com<CR><LF> */
2525  uint8_t request9_1[] = {
2526  0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
2527  0x66, 0x67, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c,
2528  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
2529  };
2530  uint32_t request9_1_len = sizeof(request9_1);
2531  /* TO:bimbs@gmail.com<CR><LF> */
2532  uint8_t request9_2[] = {
2533  0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73,
2534  0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63,
2535  0x6f, 0x6d, 0x0d, 0x0a
2536  };
2537  uint32_t request9_2_len = sizeof(request9_2);
2538  /* <CR><LF> */
2539  uint8_t request9_3[] = {
2540  0x0d, 0x0a
2541  };
2542  uint32_t request9_3_len = sizeof(request9_3);
2543  /* this is test mail2<CR><LF> */
2544  uint8_t request9_4[] = {
2545  0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
2546  0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x69,
2547  0x6c, 0x32, 0x0d, 0x0a
2548  };
2549  uint32_t request9_4_len = sizeof(request9_4);
2550  /* .<CR><LF> */
2551  uint8_t request9_5[] = {
2552  0x2e, 0x0d, 0x0a
2553  };
2554  uint32_t request9_5_len = sizeof(request9_5);
2555  /* 250 2.0.0 Ok: queued as 28CFF20BF2<CR><LF> */
2556  uint8_t reply9[] = {
2557  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
2558  0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
2559  0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
2560  0x32, 0x38, 0x43, 0x46, 0x46, 0x32, 0x30, 0x42,
2561  0x46, 0x32, 0x0d, 0x0a
2562  };
2563  uint32_t reply9_len = sizeof(reply9);
2564 
2565  /* QUIT<CR><LF> */
2566  uint8_t request10[] = {
2567  0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
2568  };
2569  uint32_t request10_len = sizeof(request10);
2570  /* 221 2.0.0 Bye<CR><LF> */
2571  uint8_t reply10[] = {
2572  0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
2573  0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
2574  };
2575  uint32_t reply10_len = sizeof(reply10);
2576 
2577  TcpSession ssn;
2579 
2580  memset(&f, 0, sizeof(f));
2581  memset(&ssn, 0, sizeof(ssn));
2582 
2583  FLOW_INITIALIZE(&f);
2584  f.protoctx = (void *)&ssn;
2585  f.proto = IPPROTO_TCP;
2586  f.alproto = ALPROTO_SMTP;
2587 
2588  StreamTcpInitConfig(true);
2589  SMTPTestInitConfig();
2590 
2591  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2592  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
2593  if (r != 0) {
2594  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2595  goto end;
2596  }
2597  SMTPState *smtp_state = f.alstate;
2598  if (smtp_state == NULL) {
2599  printf("no smtp state: ");
2600  goto end;
2601  }
2602  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2604  printf("smtp parser in inconsistent state\n");
2605  goto end;
2606  }
2607 
2608  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2609  STREAM_TOSERVER, request1, request1_len);
2610  if (r != 0) {
2611  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2612  goto end;
2613  }
2614  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2615  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2617  printf("smtp parser in inconsistent state\n");
2618  goto end;
2619  }
2620 
2621  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2622  STREAM_TOCLIENT, reply1, reply1_len);
2623  if (r != 0) {
2624  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2625  goto end;
2626  }
2627  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2629  printf("smtp parser in inconsistent state\n");
2630  goto end;
2631  }
2632 
2633  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2634  STREAM_TOSERVER, request2, request2_len);
2635  if (r != 0) {
2636  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2637  goto end;
2638  }
2639  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2640  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2642  printf("smtp parser in inconsistent state\n");
2643  goto end;
2644  }
2645 
2646  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2647  STREAM_TOCLIENT, reply2, reply2_len);
2648  if (r != 0) {
2649  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2650  goto end;
2651  }
2652  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2654  printf("smtp parser in inconsistent state\n");
2655  goto end;
2656  }
2657 
2658  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2659  STREAM_TOSERVER, request3, request3_len);
2660  if (r != 0) {
2661  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2662  goto end;
2663  }
2664  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2665  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2667  printf("smtp parser in inconsistent state\n");
2668  goto end;
2669  }
2670 
2671  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2672  STREAM_TOCLIENT, reply3, reply3_len);
2673  if (r != 0) {
2674  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2675  goto end;
2676  }
2677  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2679  printf("smtp parser in inconsistent state\n");
2680  goto end;
2681  }
2682 
2683  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2684  STREAM_TOSERVER, request4, request4_len);
2685  if (r != 0) {
2686  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2687  goto end;
2688  }
2689  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2690  smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
2692  printf("smtp parser in inconsistent state\n");
2693  goto end;
2694  }
2695 
2696  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2697  STREAM_TOCLIENT, reply4, reply4_len);
2698  if (r != 0) {
2699  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2700  goto end;
2701  }
2702  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2703  smtp_state->parser_state !=
2705  printf("smtp parser in inconsistent state\n");
2706  goto end;
2707  }
2708 
2709  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2710  STREAM_TOSERVER, request5_1, request5_1_len);
2711  if (r != 0) {
2712  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2713  goto end;
2714  }
2715  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2716  smtp_state->parser_state !=
2718 
2719  printf("smtp parser in inconsistent state\n");
2720  goto end;
2721  }
2722 
2723  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2724  STREAM_TOSERVER, request5_2, request5_2_len);
2725  if (r != 0) {
2726  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2727  goto end;
2728  }
2729  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2730  smtp_state->parser_state !=
2732 
2733  printf("smtp parser in inconsistent state\n");
2734  goto end;
2735  }
2736 
2737  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2738  STREAM_TOSERVER, request5_3, request5_3_len);
2739  if (r != 0) {
2740  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2741  goto end;
2742  }
2743  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2744  smtp_state->parser_state !=
2746 
2747  printf("smtp parser in inconsistent state\n");
2748  goto end;
2749  }
2750 
2751  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2752  STREAM_TOSERVER, request5_4, request5_4_len);
2753  if (r != 0) {
2754  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2755  goto end;
2756  }
2757  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2758  smtp_state->parser_state !=
2760 
2761  printf("smtp parser in inconsistent state\n");
2762  goto end;
2763  }
2764 
2765  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2766  STREAM_TOSERVER, request5_5, request5_5_len);
2767  if (r != 0) {
2768  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2769  goto end;
2770  }
2771  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2772  smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
2774  printf("smtp parser in inconsistent state\n");
2775  goto end;
2776  }
2777 
2778  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2779  STREAM_TOCLIENT, reply5, reply5_len);
2780  if (r != 0) {
2781  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2782  goto end;
2783  }
2784  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2786  printf("smtp parser in inconsistent state\n");
2787  goto end;
2788  }
2789 
2790  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2791  STREAM_TOSERVER, request6, request6_len);
2792  if (r != 0) {
2793  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2794  goto end;
2795  }
2796  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2797  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2799  printf("smtp parser in inconsistent state\n");
2800  goto end;
2801  }
2802 
2803  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2804  STREAM_TOCLIENT, reply6, reply6_len);
2805  if (r != 0) {
2806  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2807  goto end;
2808  }
2809  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2811  printf("smtp parser in inconsistent state\n");
2812  goto end;
2813  }
2814 
2815  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2816  STREAM_TOSERVER, request7, request7_len);
2817  if (r != 0) {
2818  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2819  goto end;
2820  }
2821  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2822  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2824  printf("smtp parser in inconsistent state\n");
2825  goto end;
2826  }
2827 
2828  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2829  STREAM_TOCLIENT, reply7, reply7_len);
2830  if (r != 0) {
2831  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2832  goto end;
2833  }
2834  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2836  printf("smtp parser in inconsistent state\n");
2837  goto end;
2838  }
2839 
2840  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2841  STREAM_TOSERVER, request8, request8_len);
2842  if (r != 0) {
2843  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2844  goto end;
2845  }
2846  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2847  smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
2849  printf("smtp parser in inconsistent state\n");
2850  goto end;
2851  }
2852 
2853  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2854  STREAM_TOCLIENT, reply8, reply8_len);
2855  if (r != 0) {
2856  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2857  goto end;
2858  }
2859  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2860  smtp_state->parser_state !=
2862  printf("smtp parser in inconsistent state\n");
2863  goto end;
2864  }
2865 
2866  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2867  STREAM_TOSERVER, request9_1, request9_1_len);
2868  if (r != 0) {
2869  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2870  goto end;
2871  }
2872  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2873  smtp_state->parser_state !=
2875 
2876  printf("smtp parser in inconsistent state\n");
2877  goto end;
2878  }
2879 
2880  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2881  STREAM_TOSERVER, request9_2, request9_2_len);
2882  if (r != 0) {
2883  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2884  goto end;
2885  }
2886  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2887  smtp_state->parser_state !=
2889 
2890  printf("smtp parser in inconsistent state\n");
2891  goto end;
2892  }
2893 
2894  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2895  STREAM_TOSERVER, request9_3, request9_3_len);
2896  if (r != 0) {
2897  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2898  goto end;
2899  }
2900  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2901  smtp_state->parser_state !=
2903 
2904  printf("smtp parser in inconsistent state\n");
2905  goto end;
2906  }
2907 
2908  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2909  STREAM_TOSERVER, request9_4, request9_4_len);
2910  if (r != 0) {
2911  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2912  goto end;
2913  }
2914  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2915  smtp_state->parser_state !=
2917 
2918  printf("smtp parser in inconsistent state\n");
2919  goto end;
2920  }
2921 
2922  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2923  STREAM_TOSERVER, request9_5, request9_5_len);
2924  if (r != 0) {
2925  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2926  goto end;
2927  }
2928  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2929  smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
2931  printf("smtp parser in inconsistent state\n");
2932  goto end;
2933  }
2934 
2935  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2936  STREAM_TOCLIENT, reply9, reply9_len);
2937  if (r != 0) {
2938  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2939  goto end;
2940  }
2941  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2943  printf("smtp parser in inconsistent state\n");
2944  goto end;
2945  }
2946 
2947  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2948  STREAM_TOSERVER, request10, request10_len);
2949  if (r != 0) {
2950  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2951  goto end;
2952  }
2953  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2954  smtp_state->cmds[0] != SMTP_COMMAND_QUIT ||
2956  printf("smtp parser in inconsistent state\n");
2957  goto end;
2958  }
2959 
2960  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
2961  STREAM_TOCLIENT, reply10, reply10_len);
2962  if (r != 0) {
2963  printf("smtp check returned %" PRId32 ", expected 0: ", r);
2964  goto end;
2965  }
2966  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2968  printf("smtp parser in inconsistent state\n");
2969  goto end;
2970  }
2971 
2972  result = 1;
2973 end:
2974  if (alp_tctx != NULL)
2976  StreamTcpFreeConfig(true);
2977  FLOW_DESTROY(&f);
2978  return result;
2979 }
2980 
2981 /**
2982  * \test Testing parsing pipelined commands.
2983  */
2984 static int SMTPParserTest03(void)
2985 {
2986  int result = 0;
2987  Flow f;
2988  int r = 0;
2989 
2990  /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
2991  uint8_t welcome_reply[] = {
2992  0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
2993  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2994  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2995  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
2996  0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
2997  0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
2998  };
2999  uint32_t welcome_reply_len = sizeof(welcome_reply);
3000 
3001  /* EHLO boo.com<CR><LF> */
3002  uint8_t request1[] = {
3003  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3004  0x2e, 0x63, 0x6f, 0x6d, 0x0a
3005  };
3006  uint32_t request1_len = sizeof(request1);
3007  /* 250-poona_slack_vm1.localdomain<CR><LF>
3008  * 250-PIPELINING<CR><LF>
3009  * 250-SIZE 10240000<CR><LF>
3010  * 250-VRFY<CR><LF>
3011  * 250-ETRN<CR><LF>
3012  * 250-ENHANCEDSTATUSCODES<CR><LF>
3013  * 250-8BITMIME<CR><LF>
3014  * 250 DSN<CR><LF>
3015  */
3016  uint8_t reply1[] = {
3017  0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
3018  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3019  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3020  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
3021  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
3022  0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
3023  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
3024  0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
3025  0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3026  0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
3027  0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
3028  0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
3029  0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
3030  0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
3031  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
3032  0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
3033  0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
3034  };
3035  uint32_t reply1_len = sizeof(reply1);
3036 
3037  /* MAIL FROM:pbsf@asdfs.com<CR><LF>
3038  * RCPT TO:pbsf@asdfs.com<CR><LF>
3039  * DATA<CR><LF>
3040  * Immediate data
3041  */
3042  uint8_t request2[] = {
3043  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
3044  0x4d, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
3045  0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
3046  0x0d, 0x0a, 0x52, 0x43, 0x50, 0x54, 0x20, 0x54,
3047  0x4f, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
3048  0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
3049  0x0d, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a,
3050  0x49, 0x6d, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74,
3051  0x65, 0x20, 0x64, 0x61, 0x74, 0x61, 0x0d, 0x0a,
3052  };
3053  uint32_t request2_len = sizeof(request2);
3054  /* 250 2.1.0 Ok<CR><LF>
3055  * 250 2.1.5 Ok<CR><LF>
3056  * 354 End data with <CR><LF>.<CR><LF>|<CR><LF>|
3057  */
3058  uint8_t reply2[] = {
3059  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
3060  0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a, 0x32, 0x35,
3061  0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, 0x35, 0x20,
3062  0x4f, 0x6b, 0x0d, 0x0a, 0x33, 0x35, 0x34, 0x20,
3063  0x45, 0x6e, 0x64, 0x20, 0x64, 0x61, 0x74, 0x61,
3064  0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x3c, 0x43,
3065  0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x2e, 0x3c,
3066  0x43, 0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x0d,
3067  0x0a
3068  };
3069  uint32_t reply2_len = sizeof(reply2);
3070 
3071  TcpSession ssn;
3073 
3074  memset(&f, 0, sizeof(f));
3075  memset(&ssn, 0, sizeof(ssn));
3076 
3077  FLOW_INITIALIZE(&f);
3078  f.protoctx = (void *)&ssn;
3079  f.proto = IPPROTO_TCP;
3080  f.alproto = ALPROTO_SMTP;
3081 
3082  StreamTcpInitConfig(true);
3083  SMTPTestInitConfig();
3084 
3085  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3086  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
3087  if (r != 0) {
3088  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3089  goto end;
3090  }
3091  SMTPState *smtp_state = f.alstate;
3092  if (smtp_state == NULL) {
3093  printf("no smtp state: ");
3094  goto end;
3095  }
3096  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3098  printf("smtp parser in inconsistent state\n");
3099  goto end;
3100  }
3101 
3102  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3103  STREAM_TOSERVER, request1, request1_len);
3104  if (r != 0) {
3105  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3106  goto end;
3107  }
3108  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3109  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3111  printf("smtp parser in inconsistent state\n");
3112  goto end;
3113  }
3114 
3115  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3116  STREAM_TOCLIENT, reply1, reply1_len);
3117  if (r != 0) {
3118  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3119  goto end;
3120  }
3121  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3122  smtp_state->parser_state !=
3124  printf("smtp parser in inconsistent state\n");
3125  goto end;
3126  }
3127 
3128  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3129  STREAM_TOSERVER, request2, request2_len);
3130  if (r != 0) {
3131  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3132  goto end;
3133  }
3134  if (smtp_state->cmds_cnt != 3 || smtp_state->cmds_idx != 0 ||
3135  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3136  smtp_state->cmds[1] != SMTP_COMMAND_OTHER_CMD ||
3137  smtp_state->cmds[2] != SMTP_COMMAND_DATA ||
3138  smtp_state->parser_state !=
3141  printf("smtp parser in inconsistent state\n");
3142  goto end;
3143  }
3144 
3145  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3146  STREAM_TOCLIENT, reply2, reply2_len);
3147  if (r != 0) {
3148  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3149  goto end;
3150  }
3151  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3152  smtp_state->parser_state !=
3155  printf("smtp parser in inconsistent state\n");
3156  goto end;
3157  }
3158 
3159  result = 1;
3160 end:
3161  if (alp_tctx != NULL)
3163  StreamTcpFreeConfig(true);
3164  FLOW_DESTROY(&f);
3165  return result;
3166 }
3167 
3168 /*
3169  * \test Test smtp with just <LF> delimiter instead of <CR><LF>.
3170  */
3171 static int SMTPParserTest04(void)
3172 {
3173  int result = 0;
3174  Flow f;
3175  int r = 0;
3176 
3177  /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
3178  uint8_t welcome_reply[] = {
3179  0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
3180  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3181  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3182  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
3183  0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
3184  0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
3185  };
3186  uint32_t welcome_reply_len = sizeof(welcome_reply);
3187 
3188  /* EHLO boo.com<CR><LF> */
3189  uint8_t request1[] = {
3190  0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
3191  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3192  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3193  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
3194  0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
3195  0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
3196  };
3197  uint32_t request1_len = sizeof(request1);
3198 
3199  TcpSession ssn;
3201 
3202  memset(&f, 0, sizeof(f));
3203  memset(&ssn, 0, sizeof(ssn));
3204 
3205  FLOW_INITIALIZE(&f);
3206  f.protoctx = (void *)&ssn;
3207  f.proto = IPPROTO_TCP;
3208  f.alproto = ALPROTO_SMTP;
3209 
3210  StreamTcpInitConfig(true);
3211  SMTPTestInitConfig();
3212 
3213  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3214  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
3215  if (r != 0) {
3216  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3217  goto end;
3218  }
3219  SMTPState *smtp_state = f.alstate;
3220  if (smtp_state == NULL) {
3221  printf("no smtp state: ");
3222  goto end;
3223  }
3224  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3226  printf("smtp parser in inconsistent state\n");
3227  goto end;
3228  }
3229 
3230  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3231  STREAM_TOSERVER, request1, request1_len);
3232  if (r != 0) {
3233  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3234  goto end;
3235  }
3236  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3237  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3239  printf("smtp parser in inconsistent state\n");
3240  goto end;
3241  }
3242 
3243  result = 1;
3244 end:
3245  if (alp_tctx != NULL)
3247  StreamTcpFreeConfig(true);
3248  FLOW_DESTROY(&f);
3249  return result;
3250 }
3251 
3252 /*
3253  * \test Test STARTTLS fail.
3254  */
3255 static int SMTPParserTest05(void)
3256 {
3257  int result = 0;
3258  Flow f;
3259  int r = 0;
3260 
3261  /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
3262  uint8_t welcome_reply[] = {
3263  0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
3264  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3265  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3266  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
3267  0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
3268  0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
3269  };
3270  uint32_t welcome_reply_len = sizeof(welcome_reply);
3271 
3272  /* EHLO boo.com<CR><LF> */
3273  uint8_t request1[] = {
3274  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3275  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
3276  };
3277  uint32_t request1_len = sizeof(request1);
3278  /* 250-poona_slack_vm1.localdomain<CR><LF>
3279  * 250-PIPELINING<CR><LF>
3280  * 250-SIZE 10240000<CR><LF>
3281  * 250-VRFY<CR><LF>
3282  * 250-ETRN<CR><LF>
3283  * 250-ENHANCEDSTATUSCODES<CR><LF>
3284  * 250-8BITMIME<CR><LF>
3285  * 250 DSN<CR><LF>
3286  */
3287  uint8_t reply1[] = {
3288  0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
3289  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3290  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3291  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
3292  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
3293  0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
3294  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
3295  0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
3296  0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3297  0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
3298  0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
3299  0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
3300  0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
3301  0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
3302  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
3303  0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
3304  0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
3305  };
3306  uint32_t reply1_len = sizeof(reply1);
3307 
3308  /* STARTTLS<CR><LF> */
3309  uint8_t request2[] = {
3310  0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
3311  0x0d, 0x0a
3312  };
3313  uint32_t request2_len = sizeof(request2);
3314  /* 502 5.5.2 Error: command not recognized<CR><LF> */
3315  uint8_t reply2[] = {
3316  0x35, 0x30, 0x32, 0x20, 0x35, 0x2e, 0x35, 0x2e,
3317  0x32, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x3a,
3318  0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
3319  0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x63,
3320  0x6f, 0x67, 0x6e, 0x69, 0x7a, 0x65, 0x64, 0x0d,
3321  0x0a
3322  };
3323  uint32_t reply2_len = sizeof(reply2);
3324 
3325  /* QUIT<CR><LF> */
3326  uint8_t request3[] = {
3327  0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
3328 
3329  };
3330  uint32_t request3_len = sizeof(request3);
3331  /* 221 2.0.0 Bye<CR><LF> */
3332  uint8_t reply3[] = {
3333  0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
3334  0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
3335  };
3336  uint32_t reply3_len = sizeof(reply3);
3337 
3338  TcpSession ssn;
3340 
3341  memset(&f, 0, sizeof(f));
3342  memset(&ssn, 0, sizeof(ssn));
3343 
3344  FLOW_INITIALIZE(&f);
3345  f.protoctx = (void *)&ssn;
3346  f.proto = IPPROTO_TCP;
3347  f.alproto = ALPROTO_SMTP;
3348 
3349  StreamTcpInitConfig(true);
3350  SMTPTestInitConfig();
3351 
3352  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3353  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
3354  if (r != 0) {
3355  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3356  goto end;
3357  }
3358  SMTPState *smtp_state = f.alstate;
3359  if (smtp_state == NULL) {
3360  printf("no smtp state: ");
3361  goto end;
3362  }
3363  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3365  printf("smtp parser in inconsistent state\n");
3366  goto end;
3367  }
3368 
3369  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3370  STREAM_TOSERVER, request1, request1_len);
3371  if (r != 0) {
3372  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3373  goto end;
3374  }
3375  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3376  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3378  printf("smtp parser in inconsistent state\n");
3379  goto end;
3380  }
3381 
3382  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3383  STREAM_TOCLIENT, reply1, reply1_len);
3384  if (r != 0) {
3385  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3386  goto end;
3387  }
3388  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3389  smtp_state->parser_state !=
3391  printf("smtp parser in inconsistent state\n");
3392  goto end;
3393  }
3394 
3395  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3396  STREAM_TOSERVER, request2, request2_len);
3397  if (r != 0) {
3398  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3399  goto end;
3400  }
3401  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3402  smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS ||
3403  smtp_state->parser_state !=
3405  printf("smtp parser in inconsistent state\n");
3406  goto end;
3407  }
3408 
3409  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3410  STREAM_TOCLIENT, reply2, reply2_len);
3411  if (r != 0) {
3412  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3413  goto end;
3414  }
3415  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3416  smtp_state->parser_state !=
3418  printf("smtp parser in inconsistent state\n");
3419  goto end;
3420  }
3421 
3422  if ((f.flags & FLOW_NOPAYLOAD_INSPECTION) ||
3424  (((TcpSession *)f.protoctx)->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) ||
3425  (((TcpSession *)f.protoctx)->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
3426  goto end;
3427  }
3428 
3429  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3430  STREAM_TOSERVER, request3, request3_len);
3431  if (r != 0) {
3432  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3433  goto end;
3434  }
3435  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3436  smtp_state->cmds[0] != SMTP_COMMAND_QUIT ||
3437  smtp_state->parser_state !=
3439  printf("smtp parser in inconsistent state\n");
3440  goto end;
3441  }
3442 
3443  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3444  STREAM_TOCLIENT, reply3, reply3_len);
3445  if (r != 0) {
3446  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3447  goto end;
3448  }
3449  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3450  smtp_state->parser_state !=
3452  printf("smtp parser in inconsistent state\n");
3453  goto end;
3454  }
3455 
3456  result = 1;
3457 end:
3458  if (alp_tctx != NULL)
3460  StreamTcpFreeConfig(true);
3461  FLOW_DESTROY(&f);
3462  return result;
3463 }
3464 
3465 /**
3466  * \test Test multiple DATA commands(full mail transactions).
3467  */
3468 static int SMTPParserTest06(void)
3469 {
3470  int result = 0;
3471  Flow f;
3472  int r = 0;
3473 
3474  uint8_t welcome_reply[] = {
3475  0x32, 0x32, 0x30, 0x20, 0x62, 0x61, 0x79, 0x30,
3476  0x2d, 0x6d, 0x63, 0x36, 0x2d, 0x66, 0x31, 0x30,
3477  0x2e, 0x62, 0x61, 0x79, 0x30, 0x2e, 0x68, 0x6f,
3478  0x74, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f,
3479  0x6d, 0x20, 0x53, 0x65, 0x6e, 0x64, 0x69, 0x6e,
3480  0x67, 0x20, 0x75, 0x6e, 0x73, 0x6f, 0x6c, 0x69,
3481  0x63, 0x69, 0x74, 0x65, 0x64, 0x20, 0x63, 0x6f,
3482  0x6d, 0x6d, 0x65, 0x72, 0x63, 0x69, 0x61, 0x6c,
3483  0x20, 0x6f, 0x72, 0x20, 0x62, 0x75, 0x6c, 0x6b,
3484  0x20, 0x65, 0x2d, 0x6d, 0x61, 0x69, 0x6c, 0x20,
3485  0x74, 0x6f, 0x20, 0x4d, 0x69, 0x63, 0x72, 0x6f,
3486  0x73, 0x6f, 0x66, 0x74, 0x27, 0x73, 0x20, 0x63,
3487  0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x20,
3488  0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20,
3489  0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x68, 0x69,
3490  0x62, 0x69, 0x74, 0x65, 0x64, 0x2e, 0x20, 0x4f,
3491  0x74, 0x68, 0x65, 0x72, 0x20, 0x72, 0x65, 0x73,
3492  0x74, 0x72, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e,
3493  0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x66, 0x6f,
3494  0x75, 0x6e, 0x64, 0x20, 0x61, 0x74, 0x20, 0x68,
3495  0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x72,
3496  0x69, 0x76, 0x61, 0x63, 0x79, 0x2e, 0x6d, 0x73,
3497  0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x41, 0x6e,
3498  0x74, 0x69, 0x2d, 0x73, 0x70, 0x61, 0x6d, 0x2f,
3499  0x2e, 0x20, 0x56, 0x69, 0x6f, 0x6c, 0x61, 0x74,
3500  0x69, 0x6f, 0x6e, 0x73, 0x20, 0x77, 0x69, 0x6c,
3501  0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74,
3502  0x20, 0x69, 0x6e, 0x20, 0x75, 0x73, 0x65, 0x20,
3503  0x6f, 0x66, 0x20, 0x65, 0x71, 0x75, 0x69, 0x70,
3504  0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x63,
3505  0x61, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20,
3506  0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e,
3507  0x69, 0x61, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6f,
3508  0x74, 0x68, 0x65, 0x72, 0x20, 0x73, 0x74, 0x61,
3509  0x74, 0x65, 0x73, 0x2e, 0x20, 0x46, 0x72, 0x69,
3510  0x2c, 0x20, 0x31, 0x36, 0x20, 0x46, 0x65, 0x62,
3511  0x20, 0x32, 0x30, 0x30, 0x37, 0x20, 0x30, 0x35,
3512  0x3a, 0x30, 0x33, 0x3a, 0x32, 0x33, 0x20, 0x2d,
3513  0x30, 0x38, 0x30, 0x30, 0x20, 0x0d, 0x0a
3514  };
3515  uint32_t welcome_reply_len = sizeof(welcome_reply);
3516 
3517  uint8_t request1[] = {
3518  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x45, 0x58, 0x43,
3519  0x48, 0x41, 0x4e, 0x47, 0x45, 0x32, 0x2e, 0x63,
3520  0x67, 0x63, 0x65, 0x6e, 0x74, 0x2e, 0x6d, 0x69,
3521  0x61, 0x6d, 0x69, 0x2e, 0x65, 0x64, 0x75, 0x0d,
3522  0x0a
3523  };
3524  uint32_t request1_len = sizeof(request1);
3525 
3526  uint8_t reply1[] = {
3527  0x32, 0x35, 0x30, 0x2d, 0x62, 0x61, 0x79, 0x30,
3528  0x2d, 0x6d, 0x63, 0x36, 0x2d, 0x66, 0x31, 0x30,
3529  0x2e, 0x62, 0x61, 0x79, 0x30, 0x2e, 0x68, 0x6f,
3530  0x74, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f,
3531  0x6d, 0x20, 0x28, 0x33, 0x2e, 0x33, 0x2e, 0x31,
3532  0x2e, 0x34, 0x29, 0x20, 0x48, 0x65, 0x6c, 0x6c,
3533  0x6f, 0x20, 0x5b, 0x31, 0x32, 0x39, 0x2e, 0x31,
3534  0x37, 0x31, 0x2e, 0x33, 0x32, 0x2e, 0x35, 0x39,
3535  0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53,
3536  0x49, 0x5a, 0x45, 0x20, 0x32, 0x39, 0x36, 0x39,
3537  0x36, 0x30, 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35,
3538  0x30, 0x2d, 0x38, 0x62, 0x69, 0x74, 0x6d, 0x69,
3539  0x6d, 0x65, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3540  0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x4d, 0x49,
3541  0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3542  0x43, 0x48, 0x55, 0x4e, 0x4b, 0x49, 0x4e, 0x47,
3543  0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x41, 0x55,
3544  0x54, 0x48, 0x20, 0x4c, 0x4f, 0x47, 0x49, 0x4e,
3545  0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x41, 0x55,
3546  0x54, 0x48, 0x3d, 0x4c, 0x4f, 0x47, 0x49, 0x4e,
3547  0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20, 0x4f, 0x4b,
3548  0x0d, 0x0a
3549  };
3550  uint32_t reply1_len = sizeof(reply1);
3551 
3552  /* MAIL FROM:asdff@asdf.com<CR><LF> */
3553  uint8_t request2[] = {
3554  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
3555  0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
3556  0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
3557  0x0d, 0x0a
3558  };
3559  uint32_t request2_len = sizeof(request2);
3560  /* 250 2.1.0 Ok<CR><LF> */
3561  uint8_t reply2[] = {
3562  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
3563  0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
3564  };
3565  uint32_t reply2_len = sizeof(reply2);
3566 
3567  /* RCPT TO:bimbs@gmail.com<CR><LF> */
3568  uint8_t request3[] = {
3569  0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
3570  0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
3571  0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
3572  0x0a
3573  };
3574  uint32_t request3_len = sizeof(request3);
3575  /* 250 2.1.5 Ok<CR><LF> */
3576  uint8_t reply3[] = {
3577  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
3578  0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
3579  };
3580  uint32_t reply3_len = sizeof(reply3);
3581 
3582  /* BDAT 51<CR><LF> */
3583  uint8_t request4[] = {
3584  0x42, 0x44, 0x41, 0x54, 0x20, 0x35, 0x31, 0x0d,
3585  0x0a,
3586  };
3587  uint32_t request4_len = sizeof(request4);
3588 
3589  uint8_t request5[] = {
3590  0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
3591  0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
3592  0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
3593  0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x0d, 0x0a,
3594  };
3595  uint32_t request5_len = sizeof(request5);
3596 
3597  uint8_t request6[] = {
3598  0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
3599  0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
3600  0x66, 0x0d, 0x0a,
3601  };
3602  uint32_t request6_len = sizeof(request6);
3603 
3604  TcpSession ssn;
3606 
3607  memset(&f, 0, sizeof(f));
3608  memset(&ssn, 0, sizeof(ssn));
3609 
3610  FLOW_INITIALIZE(&f);
3611  f.protoctx = (void *)&ssn;
3612  f.proto = IPPROTO_TCP;
3613  f.alproto = ALPROTO_SMTP;
3614 
3615  StreamTcpInitConfig(true);
3616  SMTPTestInitConfig();
3617 
3618  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3619  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
3620  if (r != 0) {
3621  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3622  goto end;
3623  }
3624  SMTPState *smtp_state = f.alstate;
3625  if (smtp_state == NULL) {
3626  printf("no smtp state: ");
3627  goto end;
3628  }
3629  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3631  printf("smtp parser in inconsistent state\n");
3632  goto end;
3633  }
3634 
3635  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3636  STREAM_TOSERVER, request1, request1_len);
3637  if (r != 0) {
3638  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3639  goto end;
3640  }
3641  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3642  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3644  printf("smtp parser in inconsistent state\n");
3645  goto end;
3646  }
3647 
3648  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3649  STREAM_TOCLIENT, reply1, reply1_len);
3650  if (r != 0) {
3651  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3652  goto end;
3653  }
3654  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3656  printf("smtp parser in inconsistent state\n");
3657  goto end;
3658  }
3659 
3660  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3661  STREAM_TOSERVER, request2, request2_len);
3662  if (r != 0) {
3663  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3664  goto end;
3665  }
3666  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3667  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3669  printf("smtp parser in inconsistent state\n");
3670  goto end;
3671  }
3672 
3673  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3674  STREAM_TOCLIENT, reply2, reply2_len);
3675  if (r != 0) {
3676  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3677  goto end;
3678  }
3679  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3681  printf("smtp parser in inconsistent state\n");
3682  goto end;
3683  }
3684 
3685  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3686  STREAM_TOSERVER, request3, request3_len);
3687  if (r != 0) {
3688  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3689  goto end;
3690  }
3691  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3692  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3694  printf("smtp parser in inconsistent state\n");
3695  goto end;
3696  }
3697 
3698  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3699  STREAM_TOCLIENT, reply3, reply3_len);
3700  if (r != 0) {
3701  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3702  goto end;
3703  }
3704  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3706  printf("smtp parser in inconsistent state\n");
3707  goto end;
3708  }
3709 
3710  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3711  STREAM_TOSERVER, request4, request4_len);
3712  if (r != 0) {
3713  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3714  goto end;
3715  }
3716  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3717  smtp_state->cmds[0] != SMTP_COMMAND_BDAT ||
3718  smtp_state->parser_state !=
3720  smtp_state->bdat_chunk_len != 51 || smtp_state->bdat_chunk_idx != 0) {
3721  printf("smtp parser in inconsistent state\n");
3722  goto end;
3723  }
3724 
3725  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3726  STREAM_TOSERVER, request5, request5_len);
3727  if (r != 0) {
3728  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3729  goto end;
3730  }
3731  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3732  smtp_state->parser_state !=
3734  smtp_state->bdat_chunk_len != 51 || smtp_state->bdat_chunk_idx != 32) {
3735  printf("smtp parser in inconsistent state\n");
3736  goto end;
3737  }
3738 
3739  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3740  STREAM_TOSERVER, request6, request6_len);
3741  if (r != 0) {
3742  printf("smtp check returned %" PRId32 ", expected 0: ", r);
3743  goto end;
3744  }
3745  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3747  smtp_state->bdat_chunk_len != 51 || smtp_state->bdat_chunk_idx != 51) {
3748  printf("smtp parser in inconsistent state\n");
3749  goto end;
3750  }
3751 
3752  result = 1;
3753 end:
3754  if (alp_tctx != NULL)
3756  StreamTcpFreeConfig(true);
3757  FLOW_DESTROY(&f);
3758  return result;
3759 }
3760 
3761 static int SMTPParserTest12(void)
3762 {
3763  int result = 0;
3764  Signature *s = NULL;
3765  ThreadVars th_v;
3766  Packet *p = NULL;
3767  Flow f;
3768  TcpSession ssn;
3769  DetectEngineThreadCtx *det_ctx = NULL;
3770  DetectEngineCtx *de_ctx = NULL;
3771  SMTPState *smtp_state = NULL;
3772  int r = 0;
3773 
3774  /* EHLO boo.com<CR><LF> */
3775  uint8_t request1[] = {
3776  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3777  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3778  };
3779  int32_t request1_len = sizeof(request1);
3780 
3781  /* 388<CR><LF>
3782  */
3783  uint8_t reply1[] = {
3784  0x31, 0x38, 0x38, 0x0d, 0x0a,
3785  };
3786  uint32_t reply1_len = sizeof(reply1);
3787 
3789 
3790  memset(&th_v, 0, sizeof(th_v));
3792  memset(&f, 0, sizeof(f));
3793  memset(&ssn, 0, sizeof(ssn));
3794 
3795  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
3796 
3797  FLOW_INITIALIZE(&f);
3798  f.protoctx = (void *)&ssn;
3799  f.proto = IPPROTO_TCP;
3800  f.alproto = ALPROTO_SMTP;
3801  p->flow = &f;
3805  f.alproto = ALPROTO_SMTP;
3806 
3807  StreamTcpInitConfig(true);
3808  SMTPTestInitConfig();
3809 
3811  if (de_ctx == NULL)
3812  goto end;
3813 
3814  de_ctx->flags |= DE_QUIET;
3815 
3816  s = DetectEngineAppendSig(de_ctx,"alert tcp any any -> any any "
3817  "(msg:\"SMTP event handling\"; "
3818  "app-layer-event: smtp.invalid_reply; "
3819  "sid:1;)");
3820  if (s == NULL)
3821  goto end;
3822 
3824  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
3825 
3826  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3827  STREAM_TOSERVER | STREAM_START, request1,
3828  request1_len);
3829  if (r != 0) {
3830  printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
3831  goto end;
3832  }
3833 
3834  smtp_state = f.alstate;
3835  if (smtp_state == NULL) {
3836  printf("no smtp state: ");
3837  goto end;
3838  }
3839 
3840  /* do detect */
3841  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3842 
3843  if (PacketAlertCheck(p, 1)) {
3844  printf("sid 1 matched. It shouldn't match: ");
3845  goto end;
3846  }
3847 
3848  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3849  STREAM_TOCLIENT | STREAM_TOCLIENT, reply1,
3850  reply1_len);
3851  if (r == 0) {
3852  printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
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 didn't match. Should have matched: ");
3861  goto end;
3862  }
3863 
3864  result = 1;
3865 
3866 end:
3867  UTHFreePackets(&p, 1);
3868  FLOW_DESTROY(&f);
3869  if (alp_tctx != NULL)
3871  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
3873  StreamTcpFreeConfig(true);
3875  return result;
3876 }
3877 
3878 static int SMTPParserTest13(void)
3879 {
3880  int result = 0;
3881  Signature *s = NULL;
3882  ThreadVars th_v;
3883  Packet *p = NULL;
3884  Flow f;
3885  TcpSession ssn;
3886  DetectEngineThreadCtx *det_ctx = NULL;
3887  DetectEngineCtx *de_ctx = NULL;
3888  SMTPState *smtp_state = NULL;
3889  int r = 0;
3890 
3891  /* EHLO boo.com<CR><LF> */
3892  uint8_t request1[] = {
3893  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3894  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3895  };
3896  int32_t request1_len = sizeof(request1);
3897 
3898  /* 250<CR><LF>
3899  */
3900  uint8_t reply1[] = {
3901  0x32, 0x35, 0x30, 0x0d, 0x0a,
3902  };
3903  uint32_t reply1_len = sizeof(reply1);
3904 
3905  /* MAIL FROM:pbsf@asdfs.com<CR><LF>
3906  * RCPT TO:pbsf@asdfs.com<CR><LF>
3907  * DATA<CR><LF>
3908  * STARTTLS<CR><LF>
3909  */
3910  uint8_t request2[] = {
3911  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
3912  0x4d, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
3913  0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
3914  0x0d, 0x0a, 0x52, 0x43, 0x50, 0x54, 0x20, 0x54,
3915  0x4f, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
3916  0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
3917  0x0d, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a,
3918  0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
3919  0x0d, 0x0a
3920  };
3921  uint32_t request2_len = sizeof(request2);
3922 
3924 
3925  memset(&th_v, 0, sizeof(th_v));
3927  memset(&f, 0, sizeof(f));
3928  memset(&ssn, 0, sizeof(ssn));
3929 
3930  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
3931 
3932  FLOW_INITIALIZE(&f);
3933  f.protoctx = (void *)&ssn;
3934  f.proto = IPPROTO_TCP;
3935  f.alproto = ALPROTO_SMTP;
3936  p->flow = &f;
3940  f.alproto = ALPROTO_SMTP;
3941 
3942  StreamTcpInitConfig(true);
3943  SMTPTestInitConfig();
3944 
3946  if (de_ctx == NULL)
3947  goto end;
3948 
3949  de_ctx->flags |= DE_QUIET;
3950 
3951  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
3952  "(msg:\"SMTP event handling\"; "
3953  "app-layer-event: "
3954  "smtp.invalid_pipelined_sequence; "
3955  "sid:1;)");
3956  if (s == NULL)
3957  goto end;
3958 
3960  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
3961 
3962  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3963  STREAM_TOSERVER | STREAM_START, request1,
3964  request1_len);
3965  if (r != 0) {
3966  printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
3967  goto end;
3968  }
3969 
3970  smtp_state = f.alstate;
3971  if (smtp_state == NULL) {
3972  printf("no smtp state: ");
3973  goto end;
3974  }
3975 
3976  /* do detect */
3977  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3978 
3979  if (PacketAlertCheck(p, 1)) {
3980  printf("sid 1 matched. It shouldn't match: ");
3981  goto end;
3982  }
3983 
3984  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
3985  STREAM_TOCLIENT, reply1, reply1_len);
3986  if (r != 0) {
3987  printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
3988  goto end;
3989  }
3990 
3991  /* do detect */
3992  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3993 
3994  if (PacketAlertCheck(p, 1)) {
3995  printf("sid 1 matched. It shouldn't match: ");
3996  goto end;
3997  }
3998 
3999  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4000  STREAM_TOSERVER, request2, request2_len);
4001  if (r != 0) {
4002  printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
4003  goto end;
4004  }
4005 
4006  /* do detect */
4007  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4008 
4009  if (!PacketAlertCheck(p, 1)) {
4010  printf("sid 1 didn't match. Should have matched: ");
4011  goto end;
4012  }
4013 
4014  result = 1;
4015 end:
4016  UTHFreePackets(&p, 1);
4017  FLOW_DESTROY(&f);
4018  if (alp_tctx != NULL)
4020  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
4022  StreamTcpFreeConfig(true);
4024  return result;
4025 }
4026 
4027 /**
4028  * \test Test DATA command w/MIME message.
4029  */
4030 static int SMTPParserTest14(void)
4031 {
4032  int result = 0;
4033  Flow f;
4034  int r = 0;
4035 
4036  /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
4037  static uint8_t welcome_reply[] = {
4038  0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
4039  0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
4040  0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
4041  0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
4042  0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
4043  0x0d, 0x0a
4044  };
4045  static uint32_t welcome_reply_len = sizeof(welcome_reply);
4046 
4047  /* EHLO boo.com<CR><LF> */
4048  static uint8_t request1[] = {
4049  0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
4050  0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
4051  };
4052  static uint32_t request1_len = sizeof(request1);
4053  /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
4054  * 250-SIZE 35882577<CR><LF>
4055  * 250-8BITMIME<CR><LF>
4056  * 250-STARTTLS<CR><LF>
4057  * 250 ENHANCEDSTATUSCODES<CR><LF>
4058  */
4059  static uint8_t reply1[] = {
4060  0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
4061  0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
4062  0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
4063  0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
4064  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
4065  0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
4066  0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
4067  0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
4068  0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
4069  0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
4070  0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
4071  0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
4072  0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
4073  0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
4074  0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
4075  };
4076  static uint32_t reply1_len = sizeof(reply1);
4077 
4078  /* MAIL FROM:asdff@asdf.com<CR><LF> */
4079  static uint8_t request2[] = {
4080  0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
4081  0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
4082  0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
4083  0x0d, 0x0a
4084  };
4085  static uint32_t request2_len = sizeof(request2);
4086  /* 250 2.1.0 Ok<CR><LF> */
4087  static uint8_t reply2[] = {
4088  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
4089  0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
4090  };
4091  static uint32_t reply2_len = sizeof(reply2);
4092 
4093  /* RCPT TO:bimbs@gmail.com<CR><LF> */
4094  static uint8_t request3[] = {
4095  0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
4096  0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
4097  0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
4098  0x0a
4099  };
4100  static uint32_t request3_len = sizeof(request3);
4101  /* 250 2.1.5 Ok<CR><LF> */
4102  static uint8_t reply3[] = {
4103  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
4104  0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
4105  };
4106  static uint32_t reply3_len = sizeof(reply3);
4107 
4108  /* DATA<CR><LF> */
4109  static uint8_t request4[] = {
4110  0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
4111  };
4112  static uint32_t request4_len = sizeof(request4);
4113  /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
4114  static uint8_t reply4[] = {
4115  0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
4116  0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
4117  0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
4118  0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
4119  0x4c, 0x46, 0x3e, 0x0d, 0x0a
4120  };
4121  static uint32_t reply4_len = sizeof(reply4);
4122 
4123  /* MIME_MSG */
4124  static uint64_t filesize = 133;
4125  static uint8_t request4_msg[] = {
4126  0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72,
4127  0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E,
4128  0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
4129  0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A,
4130  0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61,
4131  0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74,
4132  0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61,
4133  0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
4134  0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73,
4135  0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F,
4136  0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61,
4137  0x73, 0x65, 0x36, 0x34, 0x0D, 0x0A, 0x43, 0x6F,
4138  0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x44, 0x69,
4139  0x73, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F,
4140  0x6E, 0x3A, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63,
4141  0x68, 0x6D, 0x65, 0x6E, 0x74, 0x3B, 0x20, 0x66,
4142  0x69, 0x6C, 0x65, 0x6E, 0x61, 0x6D, 0x65, 0x3D,
4143  0x22, 0x74, 0x65, 0x73, 0x74, 0x2E, 0x65, 0x78,
4144  0x65, 0x22, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x54,
4145  0x56, 0x6F, 0x41, 0x41, 0x46, 0x42, 0x46, 0x41,
4146  0x41, 0x42, 0x4D, 0x41, 0x51, 0x45, 0x41, 0x61,
4147  0x69, 0x70, 0x59, 0x77, 0x77, 0x41, 0x41, 0x41,
4148  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
4149  0x41, 0x41, 0x44, 0x41, 0x51, 0x73, 0x42, 0x43,
4150  0x41, 0x41, 0x42, 0x41, 0x41, 0x43, 0x41, 0x41,
4151  0x41, 0x41, 0x41, 0x41, 0x48, 0x6B, 0x41, 0x41,
4152  0x41, 0x41, 0x4D, 0x41, 0x41, 0x41, 0x41, 0x65,
4153  0x51, 0x41, 0x41, 0x41, 0x41, 0x77, 0x41, 0x41,
4154  0x41, 0x41, 0x41, 0x41, 0x45, 0x41, 0x41, 0x42,
4155  0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
4156  0x41, 0x42, 0x30, 0x41, 0x41, 0x41, 0x41, 0x49,
4157  0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
4158  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
4159  0x41, 0x45, 0x41, 0x41, 0x49, 0x67, 0x41, 0x41,
4160  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4161  0x67, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4162  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4163  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
4164  0x41, 0x42, 0x63, 0x58, 0x44, 0x59, 0x32, 0x4C,
4165  0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C,
4166  0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F,
4167  0x41, 0x3D, 0x3D, 0x0D,0x0A };
4168  static uint32_t request4_msg_len = sizeof(request4_msg);
4169 
4170  /* DATA COMPLETED */
4171  static uint8_t request4_end[] = {
4172  0x0d, 0x0a, 0x2e, 0x0d, 0x0a
4173  };
4174  static uint32_t request4_end_len = sizeof(request4_end);
4175  /* 250 2.0.0 Ok: queued as 6A1AF20BF2<CR><LF> */
4176  static uint8_t reply4_end[] = {
4177  0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
4178  0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
4179  0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
4180  0x36, 0x41, 0x31, 0x41, 0x46, 0x32, 0x30, 0x42,
4181  0x46, 0x32, 0x0d, 0x0a
4182  };
4183  static uint32_t reply4_end_len = sizeof(reply4_end);
4184 
4185  /* QUIT<CR><LF> */
4186  static uint8_t request5[] = {
4187  0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
4188  };
4189  static uint32_t request5_len = sizeof(request5);
4190  /* 221 2.0.0 Bye<CR><LF> */
4191  static uint8_t reply5[] = {
4192  0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
4193  0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
4194  };
4195  static uint32_t reply5_len = sizeof(reply5);
4196 
4197  TcpSession ssn;
4199 
4200  memset(&f, 0, sizeof(f));
4201  memset(&ssn, 0, sizeof(ssn));
4202 
4203  FLOW_INITIALIZE(&f);
4204  f.protoctx = (void *)&ssn;
4205  f.proto = IPPROTO_TCP;
4206  f.alproto = ALPROTO_SMTP;
4207 
4208  StreamTcpInitConfig(true);
4209  SMTPTestInitConfig();
4210 
4211  /* Welcome reply */
4212  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4213  STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
4214  if (r != 0) {
4215  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4216  goto end;
4217  }
4218  SMTPState *smtp_state = f.alstate;
4219  if (smtp_state == NULL) {
4220  printf("no smtp state: ");
4221  goto end;
4222  }
4223  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
4225  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4226  goto end;
4227  }
4228 
4229  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4230  STREAM_TOSERVER, request1, request1_len);
4231  if (r != 0) {
4232  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4233  goto end;
4234  }
4235  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
4236  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4238  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4239  goto end;
4240  }
4241 
4242  /* EHLO Reply */
4243  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4244  STREAM_TOCLIENT, reply1, reply1_len);
4245  if (r != 0) {
4246  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4247  goto end;
4248  }
4249 
4250  if ((smtp_state->helo_len != 7) || strncmp("boo.com", (char *)smtp_state->helo, 7)) {
4251  printf("incorrect parsing of HELO field '%s' (%d)\n", smtp_state->helo, smtp_state->helo_len);
4252  goto end;
4253  }
4254 
4255  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
4257  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4258  goto end;
4259  }
4260 
4261  /* MAIL FROM Request */
4262  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4263  STREAM_TOSERVER, request2, request2_len);
4264  if (r != 0) {
4265  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4266  goto end;
4267  }
4268  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
4269  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4271  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4272  goto end;
4273  }
4274 
4275  /* MAIL FROM Reply */
4276  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4277  STREAM_TOCLIENT, reply2, reply2_len);
4278  if (r != 0) {
4279  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4280  goto end;
4281  }
4282 
4283  if ((smtp_state->curr_tx->mail_from_len != 14) ||
4284  strncmp("asdff@asdf.com", (char *)smtp_state->curr_tx->mail_from, 14)) {
4285  printf("incorrect parsing of MAIL FROM field '%s' (%d)\n",
4286  smtp_state->curr_tx->mail_from,
4287  smtp_state->curr_tx->mail_from_len);
4288  goto end;
4289  }
4290 
4291  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
4293  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4294  goto end;
4295  }
4296 
4297  /* RCPT TO Request */
4298  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4299  STREAM_TOSERVER, request3, request3_len);
4300  if (r != 0) {
4301  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4302  goto end;
4303  }
4304  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
4305  smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4307  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4308  goto end;
4309  }
4310 
4311  /* RCPT TO Reply */
4312  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4313  STREAM_TOCLIENT, reply3, reply3_len);
4314  if (r != 0) {
4315  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4316  goto end;
4317  }
4318  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
4320  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4321  goto end;
4322  }
4323 
4324  /* Enable mime decoding */
4325  smtp_config.decode_mime = true;
4326  SCMimeSmtpConfigDecodeBase64(1);
4327  SCMimeSmtpConfigDecodeQuoted(1);
4328 
4329  /* DATA request */
4330  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4331  STREAM_TOSERVER, request4, request4_len);
4332  if (r != 0) {
4333  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4334  goto end;
4335  }
4336 
4337  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
4338  smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
4340  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4341  goto end;
4342  }
4343 
4344  /* Data reply */
4345  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4346  STREAM_TOCLIENT, reply4, reply4_len);
4347  if (r != 0) {
4348  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4349  goto end;
4350  }
4351  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
4352  smtp_state->parser_state !=
4354  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4355  goto end;
4356  }
4357 
4358  /* DATA message */
4359  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4360  STREAM_TOSERVER, request4_msg, request4_msg_len);
4361  if (r != 0) {
4362  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4363  goto end;
4364  }
4365 
4366  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
4367  smtp_state->curr_tx->mime_state == NULL ||
4368  smtp_state->parser_state !=
4370  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4371  goto end;
4372  }
4373 
4374  /* DATA . request */
4375  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4376  STREAM_TOSERVER, request4_end, request4_end_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 != 1 || smtp_state->cmds_idx != 0 ||
4383  smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
4384  smtp_state->curr_tx->mime_state == NULL ||
4386  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4387  goto end;
4388  }
4389 
4390  SMTPState *state = (SMTPState *) f.alstate;
4391  FAIL_IF_NULL(state);
4392  FAIL_IF_NULL(state->curr_tx);
4393 
4394  FileContainer *files = &state->curr_tx->files_ts;
4395  if (files != NULL && files->head != NULL) {
4396  File *file = files->head;
4397 
4398  if(strncmp((const char *)file->name, "test.exe", 8) != 0){
4399  printf("smtp-mime file name is incorrect");
4400  goto end;
4401  }
4402  if (FileTrackedSize(file) != filesize){
4403  printf("smtp-mime file size %"PRIu64" is incorrect", FileDataSize(file));
4404  goto end;
4405  }
4406  static uint8_t org_binary[] = {
4407  0x4D, 0x5A, 0x00, 0x00, 0x50, 0x45, 0x00, 0x00,
4408  0x4C, 0x01, 0x01, 0x00, 0x6A, 0x2A, 0x58, 0xC3,
4409  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4410  0x04, 0x00, 0x03, 0x01, 0x0B, 0x01, 0x08, 0x00,
4411  0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
4412  0x79, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
4413  0x79, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
4414  0x00, 0x00, 0x40, 0x00, 0x04, 0x00, 0x00, 0x00,
4415  0x04, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00,
4416  0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
4417  0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00,
4418  0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4419  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4420  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4421  0x00, 0x00, 0x00, 0x00, 0x5C, 0x5C, 0x36, 0x36,
4422  0x2E, 0x39, 0x33, 0x2E, 0x36, 0x38, 0x2E, 0x36,
4423  0x5C, 0x7A, 0x00, 0x00, 0x38,};
4424 
4426  org_binary, sizeof(org_binary)) != 1)
4427  {
4428  printf("smtp-mime file data incorrect\n");
4429  goto end;
4430  }
4431  }
4432 
4433  /* DATA . reply */
4434  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4435  STREAM_TOCLIENT, reply4_end, reply4_end_len);
4436  if (r != 0) {
4437  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4438  goto end;
4439  }
4440  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
4442  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4443  goto end;
4444  }
4445 
4446  /* QUIT Request */
4447  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4448  STREAM_TOSERVER, request5, request5_len);
4449  if (r != 0) {
4450  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4451  goto end;
4452  }
4453  if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
4454  smtp_state->cmds[0] != SMTP_COMMAND_QUIT ||
4456  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4457  goto end;
4458  }
4459 
4460  /* QUIT Reply */
4461  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_SMTP,
4462  STREAM_TOCLIENT, reply5, reply5_len);
4463  if (r != 0) {
4464  printf("smtp check returned %" PRId32 ", expected 0: ", r);
4465  goto end;
4466  }
4467  if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
4469  printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4470  goto end;
4471  }
4472 
4473  result = 1;
4474 end:
4475  FLOW_DESTROY(&f);
4476  if (alp_tctx != NULL)
4478  StreamTcpFreeConfig(true);
4479  return result;
4480 }
4481 
4482 #endif /* UNITTESTS */
4483 
4485 {
4486 #ifdef UNITTESTS
4487  UtRegisterTest("SMTPParserTest01", SMTPParserTest01);
4488  UtRegisterTest("SMTPParserTest02", SMTPParserTest02);
4489  UtRegisterTest("SMTPParserTest03", SMTPParserTest03);
4490  UtRegisterTest("SMTPParserTest04", SMTPParserTest04);
4491  UtRegisterTest("SMTPParserTest05", SMTPParserTest05);
4492  UtRegisterTest("SMTPParserTest06", SMTPParserTest06);
4493  UtRegisterTest("SMTPParserTest12", SMTPParserTest12);
4494  UtRegisterTest("SMTPParserTest13", SMTPParserTest13);
4495  UtRegisterTest("SMTPParserTest14", SMTPParserTest14);
4496 #endif /* UNITTESTS */
4497 }
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:403
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:48
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:376
AppProto
uint16_t AppProto
Definition: app-layer-protos.h:87
PacketAlertCheck
int PacketAlertCheck(Packet *p, uint32_t sid)
Check if a certain sid alerted, this is used in the test functions.
Definition: detect-engine-alert.c:144
StreamTcpReassemblySetMinInspectDepth
void StreamTcpReassemblySetMinInspectDepth(TcpSession *ssn, int direction, uint32_t depth)
Definition: stream-tcp-reassemble.c:2171
SCAppLayerProtoDetectPMRegisterPatternCI
int SCAppLayerProtoDetectPMRegisterPatternCI(uint8_t ipproto, AppProto alproto, const char *pattern, uint16_t depth, uint16_t offset, uint8_t direction)
Registers a case-insensitive pattern for protocol detection.
Definition: app-layer-detect-proto.c:1673
STREAMING_BUFFER_CONFIG_INITIALIZER
#define STREAMING_BUFFER_CONFIG_INITIALIZER
Definition: util-streaming-buffer.h:74
SMTPConfig::decode_mime
bool decode_mime
Definition: app-layer-smtp.h: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:354
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:981
th_v
ThreadVars * th_v
Definition: fuzz_iprep.c:20
AppLayerParserRegisterStateProgressCompletionStatus
void AppLayerParserRegisterStateProgressCompletionStatus(AppProto alproto, const int ts, const int tc)
Definition: app-layer-parser.c:584
SMTPState_::toserver_last_data_stamp
uint64_t toserver_last_data_stamp
Definition: app-layer-smtp.h: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:66
SMTPTransaction_::progress_tc
uint8_t progress_tc
Definition: app-layer-smtp.h:95
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:2872
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:231
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:330
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:3058
FILEDATA_CONTENT_LIMIT
#define FILEDATA_CONTENT_LIMIT
Definition: app-layer-smtp.c:59
SMTP_REPLY_334
@ SMTP_REPLY_334
Definition: app-layer-smtp.c: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:370
DetectEngineAppendSig
Signature * DetectEngineAppendSig(DetectEngineCtx *, const char *)
Parse and append a Signature into the Detection Engine Context signature list.
Definition: detect-parse.c:3802
SMTPThreadCtx_
Definition: app-layer-smtp.c: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:433
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:1300
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:3620
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:497
SMTPInput
struct SMTPInput_ SMTPInput
AppLayerParserRegisterGetEventInfo
void AppLayerParserRegisterGetEventInfo(uint8_t ipproto, AppProto alproto, int(*StateGetEventInfo)(const char *event_name, uint8_t *event_id, AppLayerEventType *event_type))
Definition: app-layer-parser.c:663
smtp_config
SMTPConfig smtp_config
Definition: app-layer-smtp.c: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:186
FILE_NOMD5
#define FILE_NOMD5
Definition: util-file.h:114
RunmodeIsUnittests
int RunmodeIsUnittests(void)
Definition: suricata.c:292
SCLogInfo
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:232
SMTP_REPLY_554
@ SMTP_REPLY_554
Definition: app-layer-smtp.c: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:1713
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:2295
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:3865
SCAppLayerProtoDetectPMRegisterPatternCIwPP
int SCAppLayerProtoDetectPMRegisterPatternCIwPP(uint8_t ipproto, AppProto alproto, const char *pattern, uint16_t depth, uint16_t offset, uint8_t direction, ProbingParserFPtr PPFunc, uint16_t pp_min_depth, uint16_t pp_max_depth)
Definition: app-layer-detect-proto.c:1663
SMTP_COMMAND_QUIT
#define SMTP_COMMAND_QUIT
Definition: app-layer-smtp.c:98
SMTP_PARSER_STATE_PIPELINING_SERVER
#define SMTP_PARSER_STATE_PIPELINING_SERVER
Definition: app-layer-smtp.c:81
AppLayerParserRegisterStateDataFunc
void AppLayerParserRegisterStateDataFunc(uint8_t ipproto, AppProto alproto, AppLayerStateData *(*GetStateData)(void *state))
Definition: app-layer-parser.c:684
FileSetInspectSizes
void FileSetInspectSizes(File *file, const uint32_t win, const uint32_t min)
Definition: util-file.c:842
SMTPString_
Definition: app-layer-smtp.h: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:179
SMTP_REPLY_402
@ SMTP_REPLY_402
Definition: app-layer-smtp.c:291
MpmTableElmt_::DestroyCtx
void(* DestroyCtx)(struct MpmCtx_ *)
Definition: util-mpm.h:158
AppLayerResult::status
int32_t status
Definition: app-layer-parser.h:115
FileCloseFile
int FileCloseFile(FileContainer *ffc, const StreamingBufferConfig *sbcfg, const uint8_t *data, uint32_t data_len, uint16_t flags)
Close a File.
Definition: util-file.c:1050
SCFree
#define SCFree(p)
Definition: util-mem.h:61
SMTPLine_::delim_len
uint8_t delim_len
Definition: app-layer-smtp.c:124
Flow_::alproto_ts
AppProto alproto_ts
Definition: flow.h:451
SMTP_REPLY_221
@ SMTP_REPLY_221
Definition: app-layer-smtp.c:281
Flow_::alstate
void * alstate
Definition: flow.h:479
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:682
SMTP_LINE_BUFFER_LIMIT
#define SMTP_LINE_BUFFER_LIMIT
Definition: app-layer-smtp.h:33
SMTP_REPLY_450
@ SMTP_REPLY_450
Definition: app-layer-smtp.c: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:233
DetectEngineCtxInit
DetectEngineCtx * DetectEngineCtxInit(void)
Definition: detect-engine.c:2833
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:2100
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:983
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:197
MpmCtx_
Definition: util-mpm.h:97
TcpSession_
Definition: stream-tcp-private.h:283
SMTPState_::cmds_buffer_len
uint16_t cmds_buffer_len
Definition: app-layer-smtp.h:160
SMTPParserRegisterTests
void SMTPParserRegisterTests(void)
Definition: app-layer-smtp.c:4484
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:450
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
SMTP_DECODER_EVENT_INVALID_REPLY
@ SMTP_DECODER_EVENT_INVALID_REPLY
Definition: app-layer-smtp.h:36
util-enum.h
ThreadVars_::stats
StatsThreadContext stats
Definition: threadvars.h:121
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:288
SCConfNode_
Definition: conf.h:37
StatsThreadCleanup
void StatsThreadCleanup(StatsThreadContext *stats)
Definition: counters.c:1429
SCConfNode_::val
char * val
Definition: conf.h:39
SMTP_DECODER_EVENT_FAILED_PROTOCOL_CHANGE
@ SMTP_DECODER_EVENT_FAILED_PROTOCOL_CHANGE
Definition: app-layer-smtp.h:46
SMTPParserCleanup
void SMTPParserCleanup(void)
Free memory allocated for global SMTP parser state.
Definition: app-layer-smtp.c:2158
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